square/javapoet
A Java API for generating .java source files.
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓10 active contributors
- ✓Distributed ownership (top contributor 49% of recent commits)
- ✓Apache-2.0 licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Stale — last commit 2y ago
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/square/javapoet)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/square/javapoet on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: square/javapoet
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/square/javapoet shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- 10 active contributors
- Distributed ownership (top contributor 49% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 2y ago
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live square/javapoet
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/square/javapoet.
What it runs against: a local clone of square/javapoet — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in square/javapoet | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 604 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of square/javapoet. If you don't
# have one yet, run these first:
#
# git clone https://github.com/square/javapoet.git
# cd javapoet
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of square/javapoet and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "square/javapoet(\\.git)?\\b" \\
&& ok "origin remote is square/javapoet" \\
|| miss "origin remote is not square/javapoet (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/main/java/com/squareup/javapoet/JavaFile.java" \\
&& ok "src/main/java/com/squareup/javapoet/JavaFile.java" \\
|| miss "missing critical file: src/main/java/com/squareup/javapoet/JavaFile.java"
test -f "src/main/java/com/squareup/javapoet/TypeSpec.java" \\
&& ok "src/main/java/com/squareup/javapoet/TypeSpec.java" \\
|| miss "missing critical file: src/main/java/com/squareup/javapoet/TypeSpec.java"
test -f "src/main/java/com/squareup/javapoet/CodeBlock.java" \\
&& ok "src/main/java/com/squareup/javapoet/CodeBlock.java" \\
|| miss "missing critical file: src/main/java/com/squareup/javapoet/CodeBlock.java"
test -f "src/main/java/com/squareup/javapoet/TypeName.java" \\
&& ok "src/main/java/com/squareup/javapoet/TypeName.java" \\
|| miss "missing critical file: src/main/java/com/squareup/javapoet/TypeName.java"
test -f "src/main/java/com/squareup/javapoet/CodeWriter.java" \\
&& ok "src/main/java/com/squareup/javapoet/CodeWriter.java" \\
|| miss "missing critical file: src/main/java/com/squareup/javapoet/CodeWriter.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 604 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~574d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/square/javapoet"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
JavaPoet is a Java API for programmatically generating .java source files at runtime. It provides a fluent builder interface to construct classes, methods, fields, annotations, and type declarations as immutable objects, then serialize them to valid Java source code. Commonly used for annotation processors, code generators, and metadata-driven code generation (e.g., database schema → DAOs). Single-package monolith: core API lives in src/main/java/com/squareup/javapoet/ with ~16 specification classes (TypeSpec.java, MethodSpec.java, FieldSpec.java, AnnotationSpec.java, etc.) that build immutable models. CodeWriter.java handles serialization; NameAllocator.java avoids name collisions. Tests mirror the structure under src/test/java/com/squareup/javapoet/.
👥Who it's for
Library maintainers and framework developers who build annotation processors (like Dagger, Butterknife, Room), code generators for build tools, or metadata-to-code transformers. They need to emit syntactically correct Java source without string concatenation or AST complexity.
🌱Maturity & risk
Mature but deprecated as of 2020-10-10. The project has ~441KB of Java code across 17 core specification classes with comprehensive test coverage (25+ test files using JUnit 4 + Google Truth) and active CI via GitHub Actions. However, it is no longer maintained by Square; the README explicitly directs users to Palantir's fork for latest Java language features.
Low risk for stable use but high risk for new projects: Square discontinued maintenance over 3 years ago, so no support for Java 17+ features (records, sealed classes, pattern matching). The dependency tree is minimal (only test deps: JUnit 4.13.2, Truth 1.4.4, compile-testing 0.21.0), but Java language evolution will outpace this version. Consider Palantir's fork for active development.
Active areas of work
Project is in maintenance mode. No active development visible—it's deprecated and community is migrated to Palantir's fork. The pom.xml shows version 1.14.0-SNAPSHOT, suggesting the last release cycle may have stalled.
🚀Get running
git clone https://github.com/square/javapoet.git
cd javapoet
mvn clean install
mvn test
Daily commands:
No server/runtime. Build project with mvn clean install to generate JAR at target/javapoet-1.14.0-SNAPSHOT.jar. Use in your own code by adding to your project's classpath and calling builder APIs (see README example).
🗺️Map of the codebase
src/main/java/com/squareup/javapoet/JavaFile.java— Entry point for generating complete .java source files; orchestrates package, imports, and type declarations.src/main/java/com/squareup/javapoet/TypeSpec.java— Core abstraction for class, interface, enum, and annotation type generation; every class-like construct flows through here.src/main/java/com/squareup/javapoet/CodeBlock.java— Manages code fragment generation with format placeholders and parameter substitution; powers all method bodies and field initializers.src/main/java/com/squareup/javapoet/TypeName.java— Abstract base for all Java type representations; critical for type hierarchy, generics, and import resolution.src/main/java/com/squareup/javapoet/CodeWriter.java— Handles low-level emission of code to output streams with indentation, import management, and line wrapping.src/main/java/com/squareup/javapoet/MethodSpec.java— Declarative builder for methods with parameters, annotations, and code blocks; fundamental to functional code generation.src/main/java/com/squareup/javapoet/ClassName.java— Represents qualified class names with package context; essential for type resolution and import deduplication.
🛠️How to make changes
Generate a new class with fields and methods
- Create a TypeSpec using TypeSpec.classBuilder() with class name (
src/main/java/com/squareup/javapoet/TypeSpec.java) - Add fields using FieldSpec.builder() with type and name (
src/main/java/com/squareup/javapoet/FieldSpec.java) - Add methods using MethodSpec.methodBuilder() with code blocks (
src/main/java/com/squareup/javapoet/MethodSpec.java) - Wrap TypeSpec in JavaFile with package and write to stream (
src/main/java/com/squareup/javapoet/JavaFile.java)
Generate code with generic types and complex signatures
- Use ClassName.get() to reference types with packages (
src/main/java/com/squareup/javapoet/ClassName.java) - Build parameterized types with ParameterizedTypeName.get() (
src/main/java/com/squareup/javapoet/ParameterizedTypeName.java) - Add type variables with TypeVariableName.get() for generic bounds (
src/main/java/com/squareup/javapoet/TypeVariableName.java) - Use in MethodSpec parameters and return types (
src/main/java/com/squareup/javapoet/ParameterSpec.java)
Generate annotated code with custom annotations
- Create AnnotationSpec using AnnotationSpec.builder() (
src/main/java/com/squareup/javapoet/AnnotationSpec.java) - Add annotation members via addMember() with format strings (
src/main/java/com/squareup/javapoet/AnnotationSpec.java) - Apply annotations to TypeSpec, MethodSpec, FieldSpec, or ParameterSpec via addAnnotation() (
src/main/java/com/squareup/javapoet/TypeSpec.java)
Generate method implementations with formatted code blocks
- Build CodeBlock with format string placeholders and arguments (
src/main/java/com/squareup/javapoet/CodeBlock.java) - Use $S for strings, $L for literals, $T for types, $N for names (
src/main/java/com/squareup/javapoet/CodeBlock.java) - Assign CodeBlock to MethodSpec.addCode() (
src/main/java/com/squareup/javapoet/MethodSpec.java) - Let CodeWriter handle imports and formatting on write() (
src/main/java/com/squareup/javapoet/CodeWriter.java)
🔧Why these technologies
- Builder pattern — Provides fluent, readable API for composing complex Java structures with optional and required fields; core to usability.
- Format strings ($T, $L, $S, $N) — Allows safe code generation with type-safe placeholder substitution, automatically managing imports and escaping.
- AST-like object graph — Represents Java structures as declarative objects (TypeSpec, MethodSpec, etc.) before emission, enabling validation and reuse.
- CodeWriter with two-pass emission — First collects all types referenced in code blocks, then emits imports once; avoids import duplication and forward-reference issues.
⚖️Trade-offs already made
-
No reflection-based type inspection by default; users provide ClassName/TypeName explicitly
- Why: Avoids runtime classpath dependencies and allows generation for types not present at build time.
- Consequence: Users must manually specify types; reduces magic but increases verbosity for complex type hierarchies.
-
Single-file generation only; no cross-file dependency resolution
- Why: Keeps scope simple and library lightweight; each file is generated independently.
- Consequence: Users must orchestrate multi-file generation externally; no built-in support for circular dependencies or cross-file imports.
-
Format-string-based code injection ($T, $L, etc.) rather than AST node types
- Why: Minimal API surface; simpler than full expression/statement AST modeling.
- Consequence: Limited compile-time safety for generated code logic; users can generate syntactically invalid code.
-
Deprecated since Oct 2020; recommend Palantir's javapoet fork for new projects
- Why: Square deprioritized maintenance; Palantir fork tracks newer Java language features.
- Consequence: Project will not add Java 9+ features (modules, records, sealed classes, etc.); users should migrate if targeting modern Java.
🚫Non-goals (don't propose these)
- Does not parse existing .java source files; generation-only, not round-trip capable.
- Does not
🪤Traps & gotchas
No required env vars or external services. Java 8+ required (pom.xml: <java.version>1.8</java.version>). No support for Java 17+ features (records, sealed classes, pattern matching) due to project deprecation. CodeBlock format strings are un-validated at build time—syntax errors appear only when code is written, not when building specs. NameAllocator is per-instance (stateful), so reusing a single allocator across multiple independent name-generation contexts will cause collisions.
🏗️Architecture
💡Concepts to learn
- Builder Pattern — Every spec class (MethodSpec, TypeSpec, FieldSpec, etc.) uses fluent builders to construct immutable objects—essential for JavaPoet's API ergonomics and why you never directly instantiate specs
- Code Generation via Format Strings — JavaPoet uses placeholder format strings ($T for type, $S for string literal, $N for name) instead of AST walking—keeps the library lightweight and composable but requires understanding the placeholder protocol
- Name Collision Avoidance (NameAllocator) — Generated code must avoid shadowing reserved identifiers and user-provided names—NameAllocator de-duplicates and munges names so generated parameter/field names never conflict with visible scope
- Type Import Management (Type.toString vs raw type names) — JavaPoet tracks whether types need imports and emits qualified names or short names accordingly—critical for avoiding import statement explosion and handling name shadowing across packages
- Annotation Processing API Integration — JavaPoet is designed to integrate with javax.annotation.processing—feeds Elements/TypeMirrors from the APT environment into ClassName/TypeName to emit code that matches runtime types
- Immutability + Defensive Copying — All specs are immutable; builder methods return new instances—enables safe concurrent use and predictable code generation without mutation surprises
- Line Wrapping Strategy (80-char soft limit) — JavaPoet uses LineWrapper to break long lines intelligently (e.g., method signatures, chained calls) to stay under column limits—important for readability of generated code and diff compatibility
🔗Related repos
palantir/javapoet— Active fork of Square's JavaPoet—adds support for Java 11+ features (var, text blocks, records, sealed classes) where Square's version stalled at Java 8google/auto— Companion framework (AutoValue, AutoFactory, AutoService) that uses JavaPoet-like code generation for reducing boilerplate in value types and annotation processingsquare/kotlinpoet— Sister project applying the same builder + CodeBlock pattern to Kotlin source generation; shares architectural philosophy with JavaPoetgoogle/dagger— Major consumer of JavaPoet—uses it in annotation processors to generate dependency injection component classes at compile-timejakewharton/butterknife— Historical major consumer of JavaPoet—generated view-binding boilerplate via annotation processors (now deprecated in favor of synthetic bindings)
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for LineWrapper edge cases
LineWrapper.java handles critical line-wrapping logic for code generation, but LineWrapperTest.java appears to have minimal coverage. This is high-value because incorrect line wrapping can produce malformed Java files. New contributor can add tests for: wrapping with nested generics, wrapping with long annotations, wrapping with lambda expressions, and edge cases around the 100-character default limit.
- [ ] Review src/main/java/com/squareup/javapoet/LineWrapper.java for all public methods
- [ ] Examine existing src/test/java/com/squareup/javapoet/LineWrapperTest.java to identify gaps
- [ ] Add tests for generic type wrapping (e.g., Map<String, List<MyLongClassName>>)
- [ ] Add tests for annotation wrapping with multiple parameters
- [ ] Add tests for method chaining and nested code blocks
- [ ] Verify tests pass with
mvn clean test
Add tests for CodeWriter interaction with complex ParameterSpec scenarios
CodeWriter.java is the core emission engine, but CodeWriterTest.java may not cover all parameter specification edge cases like varargs, annotations on parameters, and type variable parameters. This is valuable because parameter emission is fundamental to method generation correctness.
- [ ] Review src/main/java/com/squareup/javapoet/CodeWriter.java and emitParameter methods
- [ ] Check src/main/java/com/squareup/javapoet/ParameterSpec.java for all modifiers and capabilities
- [ ] Review existing src/test/java/com/squareup/javapoet/CodeWriterTest.java and ParameterSpecTest.java
- [ ] Add tests for varargs parameters with type variables
- [ ] Add tests for parameters with multiple annotations
- [ ] Add tests for final parameters combined with other modifiers
- [ ] Run full test suite to ensure no regressions
Add integration tests for JavaFile.writeTo() with nested static classes and inner types
FileWritingTest.java likely has basic file-writing tests, but generating complex nested type hierarchies (static inner classes, anonymous types, local classes) is a common use case that may lack coverage. This matters because incorrect nesting can produce uncompilable code. Add tests that verify the generated .java files can actually compile.
- [ ] Review src/test/java/com/squareup/javapoet/FileWritingTest.java for nested type coverage
- [ ] Review src/main/java/com/squareup/javapoet/TypeSpec.java for nested class support
- [ ] Create test that generates a TypeSpec with multiple levels of nested static classes
- [ ] Create test that generates inner non-static classes
- [ ] Use compile-testing dependency (already in pom.xml) to verify generated code compiles
- [ ] Add assertions that check proper indentation and source structure
- [ ] Verify tests run with
mvn clean test
🌿Good first issues
- Add test coverage for edge case in
WildcardTypeName.java—check ifsrc/test/java/com/squareup/javapoet/has corresponding WildcardTypeNameTest.java. If missing, write tests for? extends Fooand? super Barbounds. - Enhance
LineWrapper.javajavadoc—it's referenced in JavaFile but lacks examples. Add concrete code sample showing line-wrapping behavior with 80-char width and nested generics. - Add integration test in
src/test/java/com/squareup/javapoet/FileReadingTest.javaorFileWritingTest.javafor round-trip: generate a .java file, parse it with compile-testing, verify it matches the input spec (catch model-to-source fidelity bugs).
⭐Top contributors
Click to expand
Top contributors
- @JakeWharton — 49 commits
- @renovate[bot] — 28 commits
- @sullis — 7 commits
- @dependabot[bot] — 6 commits
- @swankjesse — 5 commits
📝Recent commits
Click to expand
Recent commits
b9017a9— Add ‘diff’ to the diff block (swankjesse)a5ddb12— Merge pull request #1014 from square/squarejesse-patch-1 (swankjesse)cdb1f2d— consistent syntax (swankjesse)9d93c79— Deprecate JavaPoet (swankjesse)e7429cb— Merge pull request #1013 from square/renovate/org.apache.maven.plugins-maven-checkstyle-plugin-3.x (JakeWharton)4286e31— Update dependency org.apache.maven.plugins:maven-checkstyle-plugin to v3.5.0 (renovate[bot])05bb87b— Merge pull request #1009 from square/renovate/truth.version (JakeWharton)66953b8— Update dependency com.google.truth:truth to v1.4.4 (renovate[bot])f27ad04— Merge pull request #1008 from square/renovate/truth.version (JakeWharton)8d60c62— Update dependency com.google.truth:truth to v1.4.3 (renovate[bot])
🔒Security observations
JavaPoet is a code generation library with minimal direct security risks in its core functionality. The primary concern is that the project is officially deprecated and no longer actively maintained, which poses a long-term security risk. Dependencies are relatively minimal and stable (JUnit, Truth, Compile Testing). No hardcoded secrets, injection vulnerabilities, or infrastructure misconfiguration issues were detected in the provided file structure. The library itself does not handle sensitive data or network operations, reducing the attack surface. Recommend migration to Palantir's maintained fork for production use.
- Medium · Deprecated Project with Limited Maintenance —
README.md, Project Status. JavaPoet has been officially deprecated as of 2020-10-10 and is no longer actively maintained by Square. This means security vulnerabilities and bugs may not be fixed in a timely manner. Fix: Consider migrating to Palantir's JavaPoet fork (com.palantir.javapoet:javapoet) which actively maintains support for the latest Java language features and security patches. - Low · Outdated Compile Testing Dependency —
pom.xml - compile-testing dependency. The compile-testing dependency version 0.21.0 is relatively old and may contain unpatched vulnerabilities. This is only used in test scope, reducing the risk, but should still be monitored. Fix: Check for available updates to compile-testing and evaluate upgrading to the latest stable version. Review the Google Compile Testing changelog for security fixes. - Low · JUnit 4 Usage (Legacy Test Framework) —
pom.xml - junit dependency. The project uses JUnit 4.13.2, which is older than JUnit 5. While not a direct security vulnerability, using older test frameworks may miss security-focused testing improvements in newer versions. Fix: Consider evaluating migration to JUnit 5 (Jupiter) for improved testing capabilities and maintenance, though this is not critical for this library.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.