AI for Java code: agent, tests and Spring without extra edits

In a Java project an agent is valuable while it leaves your architecture and dependencies alone. Rules, build commands, test generation and a cost estimate.

5 min · · development · агенты

An AI for Java code is useful as long as it works inside your rules: your JDK version, your dependency injection style and the libraries already in the project. Without rules, an agent will gladly add Lombok to a project that never had it, pull a new library version into pom.xml or rewrite half the service layer for one small change. Below: how to set boundaries, which build commands to give, how to generate tests, how to check the result and what it costs.

What to hand to AI in a Java project

Tasks with a clear check of the result suit an agent well:

  • unit tests for existing classes (JUnit 5, Mockito);
  • routine code: DTOs, mappers, simple repositories;
  • refactoring by example ("do it the same way as in OrderService");
  • reading stack traces, especially long Caused by chains;
  • migrations between API versions inside the project.

Tasks without verification suit it worse: "improve the architecture", "optimize". Which model copes better is not known in advance, so check on your own tasks.

Rules for the agent: the instruction file

Put an instruction file in the project root: CLAUDE.md for Claude Code or AGENTS.md for Codex (see how to write CLAUDE.md). For a Java project this minimum is useful:

bash
## Project
- Java 21, Spring Boot, Maven build (wrapper: ./mvnw).
- Dependency injection through the constructor only. No field injection.
- Lombok is not used in this project, do not add it.
- Tests: JUnit 5 and Mockito. Do not add new dependencies without asking.

## Commands
- Build and tests: `./mvnw -q test`
- One test class: `./mvnw -q test -Dtest=OrderServiceTest`
- Tests must pass before you say "done".

## Boundaries
- Do not change pom.xml, application.yml or database migrations unless asked.
- Do not rename public classes and methods outside the task.

Substitute your own versions and build type. With Gradle the commands differ: ./gradlew test for all tests and ./gradlew test --tests "com.example.OrderServiceTest" for one class. If the project has no wrapper scripts, use the installed mvn or gradle.

The file should not be long: it goes into the context of every request, and every extra paragraph is billed as input tokens.

Test generation: an example

Suppose you have a service:

bash
public class PriceService {
    private final DiscountRepository discounts;

    public PriceService(DiscountRepository discounts) {
        this.discounts = discounts;
    }

    public long finalPrice(long basePrice, String promoCode) {
        if (basePrice < 0) {
            throw new IllegalArgumentException("basePrice must be >= 0");
        }
        int percent = discounts.findPercent(promoCode).orElse(0);
        return basePrice - basePrice * percent / 100;
    }
}

A good request to the agent: "Write JUnit 5 tests for PriceService.finalPrice with Mockito. Cover: no promo code, 10 percent, 100 percent, negative price. Do not change the class itself." The expected result looks roughly like this:

bash
@ExtendWith(MockitoExtension.class)
class PriceServiceTest {

    @Mock
    DiscountRepository discounts;

    @InjectMocks
    PriceService service;

    @Test
    void noPromoCodeMeansNoDiscount() {
        when(discounts.findPercent("NONE")).thenReturn(Optional.empty());
        assertEquals(1000, service.finalPrice(1000, "NONE"));
    }

The tests need to be read, not just run. Typical problems with generated tests: they check what the code does rather than what it should do (a bug gets locked into the test); needless verify calls on implementation details; Mockito stubs that are never used, which fail in strict mode. A good trick is to ask the agent to list edge cases separately before writing code, and compare the list with your own understanding.

How to check the result

  1. Run the tests with the command from the instruction file. Green tests from a model are not proof: make sure the new tests actually fail if you break the code (temporarily change the formula).
  2. Read the whole diff: no changes in pom.xml, configs or other people's files.
  3. Check imports and dependencies: models sometimes invent library methods that do not exist. Compilation will catch that, but non-obvious cases such as outdated APIs are better checked against the library documentation.
  4. For Spring, check annotations and the Spring Boot version separately: packages and behavior change between major versions. State the version in the instruction file.

To keep the agent within bounds, Claude Code and Codex can ask for confirmation before running commands; do not turn that off on your main repository. Setup is described in the Claude Code documentation; if you work in IntelliJ, see the article on JetBrains AI Assistant.

Which model to try

We do not claim any model writes Java better. Compare by price, context and strength index (Intelligence Index, Artificial Analysis), then check 5-10 of your own tasks. Zukko prices as of October 18, 2026, $ per 1M tokens:

ModelInput / outputOfficial input / outputContextIndex
claude-opus-5-50.8 / 44 / 201M58
gpt-6.1-sol0.27 / 1.322 / 101M52
claude-sonnet-5-50.4 / 22 / 101M48
glm-5.3-flash0.04 / 0.040.15 / 0.5128K42

Calculation: tests for 30 classes

Assumption: per class 6,000 input tokens (the class, neighboring files, rules) and 1,500 output tokens (the test). Total input 30 × 6,000 = 180,000, output 30 × 1,500 = 45,000.

  • claude-sonnet-5-5: 0.18 × $0.4 + 0.045 × $2 = $0.072 + $0.09 = $0.162. At official prices: 0.18 × $2 + 0.045 × $10 = $0.36 + $0.45 = $0.81.
  • gpt-6.1-sol: 0.18 × $0.27 + 0.045 × $1.32 = $0.0486 + $0.0594 = $0.108.
  • glm-5.3-flash: 0.18 × $0.04 + 0.045 × $0.04 = $0.0072 + $0.0018 = $0.009.

This ignores cache and repeat iterations when a test has to be redone. See your real spend in the "Usage" section of the dashboard. Current list and prices: GET https://api.zukko.pro/v1/models.

Connecting

Claude Code: ANTHROPIC_BASE_URL=https://api.zukko.pro (no /v1), ANTHROPIC_AUTH_TOKEN=fetch_.... For OpenAI-compatible tools and scripts: https://api.zukko.pro/v1. If you need to call the model from the Java application itself, an example with Spring AI is in Spring AI and Claude. Create the key in the dashboard; set a daily limit while you test.

FAQ

Can I trust generated tests?

Only after reading them. Check that a test fails on broken code and that it verifies the required behavior rather than copying the implementation.

How do I stop the agent from changing pom.xml?

Write it in the instruction file and do not grant permission for edits when it asks for confirmation. Review the diff before committing.

Is a cheap model enough for Spring?

For routine work (DTOs, simple tests) often yes, but check on your code. For tangled things like transactions and configuration, compare with a stronger model.

What if the answer uses an outdated API?

State the Java and Spring Boot versions in the instruction file and ask it to reference specific classes. Check a doubtful fragment against the library documentation.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

AI for Java code: agent, tests, Maven, Gradle · Zukko