Skip to content

Instantly share code, notes, and snippets.

@charliek
Created December 10, 2025 20:28
Show Gist options
  • Select an option

  • Save charliek/37566428f9b2a54d653e79afeef136c9 to your computer and use it in GitHub Desktop.

Select an option

Save charliek/37566428f9b2a54d653e79afeef136c9 to your computer and use it in GitHub Desktop.
Jar Source Lookup

Kotlin Source Code Lookup

Project code

Project source files are in src/main/kotlin/ and src/test/kotlin/. Use standard file reading tools to examine them.

External dependencies (library code from JARs)

Use kotlin-source-lookup to view source code from project dependencies. Works for both Kotlin (.kt) and Java (.java) sources.

# Fully qualified name - most precise, use for Java libraries
kotlin-source-lookup io.modelcontextprotocol.spec.McpSchema
kotlin-source-lookup org.springframework.web.bind.annotation.RestController

# Simple class name - faster, works when name is unique
kotlin-source-lookup McpSchema
kotlin-source-lookup JsonProperty

# List all matches - find the right package for common names
kotlin-source-lookup -l Flow

# Show all matches with full source
kotlin-source-lookup -a Flow

# Search entire gradle cache (not just this project's deps)
kotlin-source-lookup --all SomeClass

# Refresh dependency cache after adding new dependencies
kotlin-source-lookup --refresh

For nested/inner classes (like McpSchema.CallToolRequest), look up the outer class and use grep:

kotlin-source-lookup McpSchema | grep -A 50 "record CallToolRequest"
kotlin-source-lookup McpSchema | grep -A 30 "class Builder"

Notes:

  • Fully qualified names work best for Java libraries (Spring, Jackson, MCP SDK, JUnit)
  • Fully qualified names may fail for Kotlin Multiplatform libraries (kotlinx.coroutines) - use simple names with -l or -a instead
  • First run in a project caches dependencies (may take a few seconds)
  • If sources aren't found, run ./gradlew idea to download them
#!/usr/bin/env bash
#
# kotlin-source-lookup - Fast source code lookup from Gradle dependencies
#
# Usage:
# kotlin-source-lookup McpSchema # Simple class name
# kotlin-source-lookup -l McpSchema # List matching JARs only
# kotlin-source-lookup -a McpSchema # Show all matches
# kotlin-source-lookup --refresh # Refresh dependency cache
# kotlin-source-lookup --all McpSchema # Search entire gradle cache (old behavior)
#
set -euo pipefail
GRADLE_CACHE="${GRADLE_CACHE:-$HOME/.gradle/caches/modules-2/files-2.1}"
DEP_CACHE_FILE=".kotlin-source-deps"
DEP_CACHE_MAX_AGE=86400 # 24 hours in seconds
LIST_ONLY=false
ALL_MATCHES=false
SEARCH_ALL_CACHE=false
REFRESH_CACHE=false
# Parse flags
while [[ $# -gt 0 ]]; do
case $1 in
-l) LIST_ONLY=true; shift ;;
-a) ALL_MATCHES=true; shift ;;
--all) SEARCH_ALL_CACHE=true; shift ;;
--refresh) REFRESH_CACHE=true; shift ;;
-h|--help)
echo "Usage: $0 [-l] [-a] [--all] [--refresh] <class-name>"
echo " -l List matching JARs only (don't extract)"
echo " -a Show all matches (default: first match only)"
echo " --all Search entire gradle cache, not just project deps"
echo " --refresh Refresh the dependency cache"
echo ""
echo "Examples:"
echo " $0 McpSchema"
echo " $0 -l Flow"
echo " $0 --all Flow # Find Flow in ANY cached library"
exit 0
;;
-*) echo "Unknown option: $1" >&2; exit 1 ;;
*) break ;;
esac
done
# Handle --refresh with no query
if $REFRESH_CACHE && [[ $# -eq 0 ]]; then
rm -f "$DEP_CACHE_FILE"
echo "Dependency cache cleared. Will regenerate on next search."
exit 0
fi
if [[ $# -lt 1 ]]; then
echo "Usage: $0 [-l] [-a] [--all] [--refresh] <class-name>" >&2
exit 1
fi
QUERY="$1"
# Convert class name to grep pattern
if [[ "$QUERY" == *.* ]]; then
CLASS_PATH="${QUERY//./\/}"
PATTERN="${CLASS_PATH}\.(kt|java)$"
else
PATTERN="/${QUERY}\.(kt|java)$"
fi
# Generate dependency cache if needed
generate_dep_cache() {
echo "Generating dependency cache (this may take a moment)..." >&2
if [[ ! -f "build.gradle.kts" && ! -f "build.gradle" ]]; then
echo "Warning: No build.gradle found, searching entire cache" >&2
SEARCH_ALL_CACHE=true
return
fi
# Get dependencies from all configurations
# Running without --configuration shows everything
local deps
deps=$(./gradlew dependencies 2>/dev/null | \
grep -oE '[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+:[0-9a-zA-Z._-]+' | \
sort -u || true)
if [[ -z "$deps" ]]; then
echo "Warning: Could not parse dependencies, searching entire cache" >&2
SEARCH_ALL_CACHE=true
return
fi
# Convert to source JAR paths
> "$DEP_CACHE_FILE"
while IFS=: read -r group artifact version; do
[[ -z "$group" ]] && continue
# Find source JARs matching this dependency (glob for hash directory)
local jar_pattern="$GRADLE_CACHE/$group/$artifact/$version/*/${artifact}-${version}-sources.jar"
for jar in $jar_pattern; do
[[ -f "$jar" ]] && echo "$jar" >> "$DEP_CACHE_FILE"
done
done <<< "$deps"
local count
count=$(wc -l < "$DEP_CACHE_FILE" | tr -d ' ')
echo "Cached $count source JARs from project dependencies" >&2
}
# Check if cache needs refresh
needs_cache_refresh() {
[[ ! -f "$DEP_CACHE_FILE" ]] && return 0
$REFRESH_CACHE && return 0
# Check age
local cache_age
if [[ "$(uname)" == "Darwin" ]]; then
cache_age=$(( $(date +%s) - $(stat -f %m "$DEP_CACHE_FILE") ))
else
cache_age=$(( $(date +%s) - $(stat -c %Y "$DEP_CACHE_FILE") ))
fi
[[ $cache_age -gt $DEP_CACHE_MAX_AGE ]] && return 0
return 1
}
# Get list of JARs to search
get_source_jars() {
if $SEARCH_ALL_CACHE; then
# Search entire gradle cache (original behavior)
if command -v fd &>/dev/null; then
fd -e jar 'sources\.jar$' "$GRADLE_CACHE" 2>/dev/null
else
find "$GRADLE_CACHE" -name '*-sources.jar' 2>/dev/null
fi
else
# Use project dependencies only
if needs_cache_refresh; then
generate_dep_cache
fi
if [[ -f "$DEP_CACHE_FILE" && -s "$DEP_CACHE_FILE" ]]; then
cat "$DEP_CACHE_FILE"
else
# Fallback to full cache search
echo "Warning: No dependency cache, searching entire cache" >&2
if command -v fd &>/dev/null; then
fd -e jar 'sources\.jar$' "$GRADLE_CACHE" 2>/dev/null
else
find "$GRADLE_CACHE" -name '*-sources.jar' 2>/dev/null
fi
fi
fi
}
# Search JAR contents
search_jar() {
local jar="$1"
if command -v zipinfo &>/dev/null; then
zipinfo -1 "$jar" 2>/dev/null | grep -E "$PATTERN" || true
else
unzip -l "$jar" 2>/dev/null | awk '{print $4}' | grep -E "$PATTERN" || true
fi
}
# Extract and display source
extract_source() {
local jar="$1"
local file="$2"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📦 JAR: ${jar##*/}"
echo "📄 File: $file"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
unzip -p "$jar" "$file" 2>/dev/null
}
# Main search
found=0
while IFS= read -r jar; do
[[ -z "$jar" ]] && continue
[[ ! -f "$jar" ]] && continue
while IFS= read -r match; do
[[ -z "$match" ]] && continue
found=$((found + 1))
if $LIST_ONLY; then
echo "$jar -> $match"
else
extract_source "$jar" "$match"
fi
# Exit after first match unless -a flag
if ! $ALL_MATCHES && ! $LIST_ONLY; then
exit 0
fi
done < <(search_jar "$jar")
done < <(get_source_jars)
if [[ $found -eq 0 ]]; then
echo "❌ No source found for: $QUERY" >&2
echo "" >&2
echo "Tips:" >&2
echo " • Ensure sources are downloaded: ./gradlew idea" >&2
echo " • Try --all to search entire gradle cache" >&2
echo " • Try --refresh to update dependency cache" >&2
echo " • Check spelling (case-sensitive)" >&2
exit 1
fi
if $LIST_ONLY; then
echo ""
echo "Found $found match(es)"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment