Kotlin/Java: Retrofit client interfaces are minted as server `Route` nodes instead of outbound `HTTP_CALLS`
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 57/100
Rechercherichtung
Start by reading the Kotlin and Java HTTP indexing paths that create Route nodes and HTTP_CALLS edges, then compare their handling of Retrofit annotations with the existing JAX-RS and RestTemplate behavior described here. Reproduce with the supplied OrderApi.kt and Java interface examples, checking both graph edge types and route paths. Done when Retrofit methods produce the expected outbound calls and paths, with no client HANDLES routes or cross-repository matches landing on the client.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Version
codebase-memory-mcp 0.12.1
Platform
Linux (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
ui
What happened, and what did you expect?
A Retrofit service interface (@GET/@POST/... from retrofit2.http, in Kotlin or Java) declares the HTTP calls
a client makes, but it is indexed as if the client served them: each annotated method becomes a Route
node of the client project with a HANDLES edge from the interface method. Three consequences:
- Outbound calls lost. The interface methods get no
HTTP_CALLSedge, socross-repo-intelligencereports
cross_http_calls: 0for a client whose whole HTTP surface is Retrofit, which is the usual shape of an
Android app. - Other callers get linked to the client. A path written with a leading slash (
@GET("/v1/orders/{id}"),
which Retrofit treats as absolute: "Endpoint values which contain a leading/are absolute",
Retrofit.java:581)
yields aRouteidentical to the server's real one.cross-repo-intelligencefrom any other project that
calls the same endpoint then emits aCROSS_HTTP_CALLSpair into the client as well as into the server, as if
the client's interface method handled the request. - Paths collapse onto
/. Any path that is not a string literal with a leading slash becomes/, so all
such methods collide on__route__GET__//__route__POST__/:- the idiomatic relative path (
@POST("v1/orders")), resolved at runtime against thebaseUrl
(Retrofit.java:560); - a Kotlin
const val, alone (@GET(ORDERS)) or in a string template (@GET("$ORDERS/{id}/status")), even
when the constant itself starts with/. Retrofit annotation arguments must be compile-time constants, so
this is a common way to share a path prefix across the methods of one interface.
- the idiomatic relative path (
Expected: see "Result vs expected" in the Reproduction section.
Reproduction
1. Code. Three dummy repos, created as /tmp/cbm-kotlin-retrofit-client, /tmp/cbm-orders-server and
/tmp/cbm-billing-caller.
Client repo /tmp/cbm-kotlin-retrofit-client, under src/main/kotlin/com/acme/client/:
// OrderApi.kt (Retrofit, Kotlin coroutines)
package com.acme.client
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
private const val ORDERS = "/v1/orders"
interface OrderApi {
@GET("/v1/orders/{id}")
suspend fun getOrder(@Path("id") id: String): String
@POST("v1/orders")
suspend fun createOrder(@Body body: String): String
@GET(ORDERS)
suspend fun listOrders(): String
@GET("$ORDERS/{id}/status")
suspend fun getOrderStatus(@Path("id") id: String): String
}
Server repo /tmp/cbm-orders-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; }
@GET @Path("/{id}/status") public String status(@PathParam("id") String id) { return id; }
@POST public String create(String body) { return body; }
}
Another caller of the same server, /tmp/cbm-billing-caller, under src/main/java/com/acme/billing/ (an inline
RestTemplate, a shape that already produces HTTP_CALLS):
// BillingJob.java
package com.acme.billing;
import org.springframework.web.client.RestTemplate;
public class BillingJob {
public String order(String id) {
return new RestTemplate().getForObject("/v1/orders/{id}", String.class, 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-kotlin-retrofit-client","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-orders-server","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-billing-caller","mode":"moderate"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (f)-[e:HANDLES]->(r:Route) RETURN f.file_path, f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (f)-[e:HTTP_CALLS]->(r) RETURN f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-orders-server","query":"MATCH (r:Route) RETURN r.qualified_name"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-kotlin-retrofit-client","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-orders-server"]}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-billing-caller","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-kotlin-retrofit-client","tmp-cbm-orders-server"]}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (h)-[e:CROSS_HTTP_CALLS]->(r) RETURN h.file_path, h.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-orders-server","query":"MATCH (h)-[e:CROSS_HTTP_CALLS]->(r) RETURN h.file_path, h.name, r.qualified_name"}'
3. Result vs expected. CLI output, trimmed to the rows.
Client HANDLES edges (expected: 0 rows; only the leading-slash literal keeps its path, the relative path and
both const val forms collapse to /):
rows: 4 (cols: f.file_path f.name r.qualified_name)
src/main/kotlin/com/acme/client/OrderApi.kt getOrder __route__GET__/v1/orders/{}
src/main/kotlin/com/acme/client/OrderApi.kt createOrder __route__POST__/
src/main/kotlin/com/acme/client/OrderApi.kt listOrders __route__GET__/
src/main/kotlin/com/acme/client/OrderApi.kt getOrderStatus __route__GET__/
Client HTTP_CALLS edges:
rows: 0 (cols: f.name r.qualified_name)
Expected 4 rows:
getOrder __route__GET__/v1/orders/{}
createOrder __route__POST__/v1/orders
listOrders __route__GET__/v1/orders
getOrderStatus __route__GET__/v1/orders/{}/status
Server Route nodes (correct):
rows: 4 (cols: r.qualified_name)
__route__GET__/v1/orders
__route__GET__/v1/orders/{}
__route__GET__/v1/orders/{}/status
__route__POST__/v1/orders
cross-repo-intelligence from the client: "cross_http_calls":0. Expected 4.
cross-repo-intelligence from the billing caller: "cross_http_calls":2 for its single call. Expected 1. The
reverse edges show the second one landing on the client's interface method:
# tmp-cbm-kotlin-retrofit-client (expected: 0 rows)
rows: 1 (cols: h.file_path h.name r.qualified_name)
src/main/kotlin/com/acme/client/OrderApi.kt getOrder __route__GET__/v1/orders/{}
# tmp-cbm-orders-server (correct)
rows: 1 (cols: h.file_path h.name r.qualified_name)
src/main/java/com/acme/server/OrderResource.java get __route__GET__/v1/orders/{}
The same holds for a Java Retrofit interface: @GET("v1/orders/{id}") and @POST("v1/orders") on a Java
interface give HANDLES to __route__GET__/ and __route__POST__/ and no HTTP_CALLS.
Related: #2668 (Java outbound calls through injected clients, format strings and request builders yield no
HTTP_CALLS; same "outbound call lost" family, different mechanism), #1248 (false Routes minted from
non-registration string literals).
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
Impact on a real codebase. On a production Kotlin Android app (29 Retrofit interfaces, 85 annotated
methods; proprietary, so only counts here):
- 85
HANDLESedges onto 67 clientRoutenodes, 0HTTP_CALLS; - 16 methods (relative paths and
const valtemplates) collapse onto__route__GET__/and
__route__POST__/; - of the 65 other distinct paths, 55 match a
HANDLES-backedRouteof the backend services the app talks to,
so classifying them as outbound calls would give the app 55 correct cross-repo links instead of 0 (the
remaining 10 are static files and third-party APIs); - 15
CROSS_HTTP_CALLSfrom call sites in 6 other repositories of the same fleet land on the app's interface
methods.
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.
- Vorherrschende Sprache
- C
- Sterne
- 45.8k
- Forks
- 3.8k
- Ø Merge
- 3 T. 8 Std.
- Gemergte PRs (30 T.)
- 195
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus DeusData/codebase-memory-mcp
-
editor/integration parsing/quality
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
DeusData/codebase-memory-mcp#2286 ·
Maintainer antworten meist innerhalb von 1 Tag
-
install writes an unsupported `args` key into the Claude Code SubagentStart hook, so it never runsOffenbug editor/integration priority/high stability/performance ux/behavior
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
DeusData/codebase-memory-mcp#2239 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
bug priority/high ux/behavior
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
DeusData/codebase-memory-mcp#2232 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
documentation editor/integration parsing/quality priority/normal
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
DeusData/codebase-memory-mcp#2169 ·
Maintainer antworten meist innerhalb von 1 Tag
-
documentation priority/normal ux/behavior
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
DeusData/codebase-memory-mcp#2050 ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in DeusData/codebase-memory-mcp
Ähnliche Issues
-
Schwierigkeit 2/5 Ein halber Tag Anfängerfreundlichkeit 62/100
php/php-src#25137 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
c3lang/c3c#3613 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
es-ude/OnDeviceTraining#511 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
STMicroelectronics/STSELib#128 ·