
# Java

Start with the [gRPC guide](../grpc.md) to get a Platform API token and download `platform.proto`. The client contract sets `java_package = "dev.reconstruct.platform.v1"` and generates separate Java classes for its messages. This example uses Gradle and the [gRPC Java protobuf plugin](https://github.com/grpc/grpc-java#generated-code).

Place `platform.proto` at `src/main/proto/platform.proto`. Add this `build.gradle`:

```groovy
plugins {
    id 'java'
    id 'application'
    id 'com.google.protobuf' version '0.9.5'
}

repositories { mavenCentral() }

def grpcVersion = '1.84.0'
dependencies {
    implementation "io.grpc:grpc-protobuf:${grpcVersion}"
    implementation "io.grpc:grpc-stub:${grpcVersion}"
    runtimeOnly "io.grpc:grpc-netty-shaded:${grpcVersion}"
    compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
}

protobuf {
    protoc { artifact = 'com.google.protobuf:protoc:3.25.8' }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
    }
    generateProtoTasks {
        all()*.plugins { grpc {} }
    }
}

application { mainClass = 'dev.reconstruct.example.Main' }
```

Gradle generates the message classes and `PlatformServiceGrpc` when it builds the project. Save this as `src/main/java/dev/reconstruct/example/Main.java`:

```java
package dev.reconstruct.example;

import dev.reconstruct.platform.v1.GetCatalogRequest;
import dev.reconstruct.platform.v1.ListCatalogsRequest;
import dev.reconstruct.platform.v1.PlatformServiceGrpc;
import io.grpc.Grpc;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.TlsChannelCredentials;
import io.grpc.stub.MetadataUtils;
import java.util.concurrent.TimeUnit;

public final class Main {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("CR_RECONSTRUCT_API_TOKEN");
        if (token == null || token.isBlank()) {
            throw new IllegalStateException("Set CR_RECONSTRUCT_API_TOKEN");
        }

        ManagedChannel channel = Grpc.newChannelBuilderForAddress(
            "reconstruct.dev", 443, TlsChannelCredentials.create()).build();
        try {
            Metadata headers = new Metadata();
            headers.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER),
                "Bearer " + token);
            var client = PlatformServiceGrpc.newBlockingStub(channel)
                .withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers))
                .withDeadlineAfter(10, TimeUnit.SECONDS);

            var page = client.listCatalogs(ListCatalogsRequest.newBuilder().setPageSize(10).build());
            for (var catalog : page.getCatalogsList()) {
                var detail = client.getCatalog(GetCatalogRequest.newBuilder()
                    .setCatalogId(catalog.getCatalogId()).build());
                System.out.println(detail.getCatalogId() + ": " + detail.getDescription());
            }
        } finally {
            channel.shutdownNow();
        }
    }
}
```

Run `gradle run` (or `./gradlew run` if your project has a Gradle wrapper). Native gRPC uses the TLS authority, not the `/api/v1` REST path.
