Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Kotlin/Java: Retrofit client interfaces are minted as server `Route` nodes instead of outbound `HTTP_CALLS`

Aperta
#2,723 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
57/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
java, kotlin
Ambito
devtools

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug parsing/quality ux/behavior
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_CALLS edge, so cross-repo-intelligence reports
    cross_http_calls: 0 for 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 a Route identical to the server's real one. cross-repo-intelligence from any other project that
    calls the same endpoint then emits a CROSS_HTTP_CALLS pair 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 the baseUrl
      (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.

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 HANDLES edges onto 67 client Route nodes, 0 HTTP_CALLS;
  • 16 methods (relative paths and const val templates) collapse onto __route__GET__/ and
    __route__POST__/;
  • of the 65 other distinct paths, 55 match a HANDLES-backed Route of 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_CALLS from 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.
Lingua principale
C
Stelle
45.8k
Fork
3.8k
Merge medio
3g 6h
PR unite (30g)
201

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di DeusData/codebase-memory-mcp

Tutte le issue di DeusData/codebase-memory-mcp

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.