or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-message-api.mddescriptors-reflection.mdextensions.mdindex.mdjson-format.mdserialization-io.mdwell-known-types.md
tile.json

json-format.mddocs/

JSON Format Support

Utilities for converting protocol buffer messages to and from JSON format, with configurable options and type registry support. This enables interoperability with JSON-based APIs and human-readable message representation in the shaded akka.protobufv3.internal.util package.

Capabilities

JsonFormat Class

Main utility class providing JSON conversion functionality for protocol buffer messages.

/**
 * Utility class to convert protobuf messages to/from JSON format.
 * Provides configurable parsing and printing with custom type registries.
 */
class JsonFormat {
    /** Create a JSON parser with default settings */
    static Parser parser();
    
    /** Create a JSON printer with default settings */
    static Printer printer();
    
    /** Create a type registry builder */
    static TypeRegistry.Builder newBuilder();
    
    /** Get empty type registry */
    static TypeRegistry emptyTypeRegistry();
}

Parser Class

Parses JSON representations into protocol buffer messages with configurable options.

/**
 * Parser for converting JSON format to protocol buffer messages.
 * Configurable with options for handling unknown fields and type resolution.
 */
static class JsonFormat.Parser {
    /** Create parser that ignores unknown JSON fields */
    Parser ignoringUnknownFields();
    
    /** Create parser with custom type registry for Any message resolution */
    Parser usingTypeRegistry(TypeRegistry registry);
    
    /** Parse JSON string into message builder */
    void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException;
    
    /** Parse JSON from Readable into message builder */
    void merge(Readable json, Message.Builder builder) throws InvalidProtocolBufferException;
    
    /** Parse JSON string into message builder with extension registry */
    void merge(String json, ExtensionRegistry extensionRegistry, Message.Builder builder)
        throws InvalidProtocolBufferException;
    
    /** Parse JSON from Readable with extension registry */
    void merge(Readable json, ExtensionRegistry extensionRegistry, Message.Builder builder)
        throws InvalidProtocolBufferException;
}

Printer Class

Converts protocol buffer messages to JSON format with configurable output options.

/**
 * Printer for converting protocol buffer messages to JSON format.
 * Configurable with options for field naming and default value inclusion.
 */
static class JsonFormat.Printer {
    /** Create printer that includes fields with default values */
    Printer includingDefaultValueFields();
    
    /** Create printer that preserves original proto field names */
    Printer preservingProtoFieldNames();
    
    /** Create printer that prints enums as integers instead of names */
    Printer printingEnumsAsInts();
    
    /** Create printer that omits whitespace for compact output */
    Printer omittingInsignificantWhitespace();
    
    /** Create printer with custom type registry for Any message resolution */
    Printer usingTypeRegistry(TypeRegistry registry);
    
    /** Convert message to JSON string */
    String print(MessageOrBuilder message) throws InvalidProtocolBufferException;
    
    /** Convert message to JSON and append to Appendable */
    void appendTo(MessageOrBuilder message, Appendable output) throws IOException;
}

TypeRegistry Class

Registry for resolving message types when parsing/printing Any messages in JSON format.

/**
 * Registry for resolving message types when working with Any messages in JSON.
 * Maps type URLs to message descriptors for dynamic type resolution.
 */
static class JsonFormat.TypeRegistry {
    /** Find descriptor by type URL */
    Descriptors.Descriptor find(String name);
    
    /** Get all registered type URLs */
    Set<String> getTypes();
    
    /** Check if type is registered */
    boolean contains(String typeUrl);
    
    /** Get empty type registry */
    static TypeRegistry getEmptyTypeRegistry();
    
    /** Create a new type registry builder */
    static Builder newBuilder();
    
    /** Type registry builder */
    static class Builder {
        /** Add message type to registry */
        Builder add(Descriptors.Descriptor messageType);
        
        /** Add multiple message types to registry */
        Builder add(Iterable<Descriptors.Descriptor> messageTypes);
        
        /** Build the type registry */
        TypeRegistry build();
    }
}

Usage Examples

Basic JSON Conversion

import akka.protobufv3.internal.util.JsonFormat;

// Convert message to JSON (assumes MyMessage exists)
// MyMessage message = MyMessage.newBuilder()
//     .setName("John Doe")
//     .setId(123)
//     .setActive(true)
//     .build();

// String json = JsonFormat.printer().print(message);
// System.out.println(json);
// Output: {"name":"John Doe","id":123,"active":true}

// Parse JSON back to message
String jsonInput = "{\"name\":\"Jane Doe\",\"id\":456,\"active\":false}";
// MyMessage.Builder builder = MyMessage.newBuilder();
// JsonFormat.parser().merge(jsonInput, builder);
// MyMessage parsed = builder.build();

Custom Printer Configuration

import akka.protobufv3.internal.util.JsonFormat;

// Create printer with custom options
JsonFormat.Printer printer = JsonFormat.printer()
    .includingDefaultValueFields()      // Include fields with default values
    .preservingProtoFieldNames()        // Use proto field names instead of JSON names
    .printingEnumsAsInts()             // Print enums as integers
    .omittingInsignificantWhitespace(); // Compact output

// Convert message with custom printer
// String compactJson = printer.print(message);

Custom Parser Configuration

import akka.protobufv3.internal.util.JsonFormat;

// Create parser that ignores unknown fields
JsonFormat.Parser parser = JsonFormat.parser()
    .ignoringUnknownFields();

// Parse JSON with unknown fields (they will be ignored)
String jsonWithExtra = "{\"name\":\"John\",\"id\":123,\"unknownField\":\"ignored\"}";
// MyMessage.Builder builder = MyMessage.newBuilder();
// parser.merge(jsonWithExtra, builder);
// MyMessage result = builder.build();

Working with Any Messages

import akka.protobufv3.internal.*;
import akka.protobufv3.internal.util.JsonFormat;

// Create type registry for Any message resolution
JsonFormat.TypeRegistry typeRegistry = JsonFormat.TypeRegistry.newBuilder()
    // .add(MyMessage.getDescriptor())
    // .add(AnotherMessage.getDescriptor())
    .build();

// Create printer with type registry
JsonFormat.Printer printer = JsonFormat.printer()
    .usingTypeRegistry(typeRegistry);

// Create parser with type registry
JsonFormat.Parser parser = JsonFormat.parser()
    .usingTypeRegistry(typeRegistry);

// Work with Any messages containing registered types
// MyMessage originalMessage = MyMessage.newBuilder()
//     .setName("example")
//     .build();

// Any anyMessage = Any.pack(originalMessage);
// String json = printer.print(anyMessage);
// 
// // Parse back
// Any.Builder anyBuilder = Any.newBuilder();
// parser.merge(json, anyBuilder);
// Any parsedAny = anyBuilder.build();
// MyMessage unpacked = parsedAny.unpack(MyMessage.class);

Working with Well-Known Types

import akka.protobufv3.internal.*;
import akka.protobufv3.internal.util.JsonFormat;

// Timestamp JSON conversion
Timestamp timestamp = Timestamp.newBuilder()
    .setSeconds(1234567890)
    .setNanos(123456789)
    .build();

String timestampJson = JsonFormat.printer().print(timestamp);
// Output: "2009-02-13T23:31:30.123456789Z"

// Duration JSON conversion  
Duration duration = Duration.newBuilder()
    .setSeconds(300)
    .setNanos(500000000)
    .build();

String durationJson = JsonFormat.printer().print(duration);
// Output: "300.500s"

// Struct JSON conversion
Struct struct = Struct.newBuilder()
    .putFields("name", Value.newBuilder()
        .setStringValue("John")
        .build())
    .putFields("age", Value.newBuilder()
        .setNumberValue(30)
        .build())
    .build();

String structJson = JsonFormat.printer().print(struct);
// Output: {"name":"John","age":30}

Error Handling

import akka.protobufv3.internal.*;
import akka.protobufv3.internal.util.JsonFormat;

try {
    // Attempt to parse invalid JSON
    String invalidJson = "{invalid json}";
    // MyMessage.Builder builder = MyMessage.newBuilder();
    JsonFormat.parser().merge(invalidJson, builder);
} catch (InvalidProtocolBufferException e) {
    System.err.println("JSON parsing failed: " + e.getMessage());
}

try {
    // Attempt to print message with missing required fields
    // MyMessage incompleteMessage = MyMessage.newBuilder().build();
    // String json = JsonFormat.printer().print(incompleteMessage);
} catch (InvalidProtocolBufferException e) {
    System.err.println("Message printing failed: " + e.getMessage());
}

Integration with I/O

import akka.protobufv3.internal.*;
import akka.protobufv3.internal.util.JsonFormat;
import java.io.*;

// Read JSON from file
JsonFormat.Parser parser = JsonFormat.parser();
// MyMessage.Builder builder = MyMessage.newBuilder();

try (FileReader reader = new FileReader("message.json")) {
    parser.merge(reader, builder);
    // MyMessage message = builder.build();
} catch (IOException e) {
    System.err.println("Failed to read JSON file: " + e.getMessage());
}

// Write JSON to file
JsonFormat.Printer printer = JsonFormat.printer()
    .includingDefaultValueFields();

try (FileWriter writer = new FileWriter("output.json")) {
    // printer.appendTo(message, writer);
} catch (IOException e) {
    System.err.println("Failed to write JSON file: " + e.getMessage());
}

Streaming JSON Processing

import akka.protobufv3.internal.*;
import akka.protobufv3.internal.util.JsonFormat;
import java.io.*;

// Process multiple JSON messages from stream
JsonFormat.Parser parser = JsonFormat.parser().ignoringUnknownFields();

try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
    String line;
    while ((line = reader.readLine()) != null) {
        if (!line.trim().isEmpty()) {
            // MyMessage.Builder builder = MyMessage.newBuilder();
            // parser.merge(line, builder);
            // MyMessage message = builder.build();
            // processMessage(message);
        }
    }
} catch (IOException e) {
    System.err.println("Stream processing failed: " + e.getMessage());
}

Custom Field Naming

import akka.protobufv3.internal.util.JsonFormat;

// Default behavior: proto field names converted to JSON camelCase
// Proto field: user_name -> JSON field: userName

// Preserve original proto field names
JsonFormat.Printer preservingPrinter = JsonFormat.printer()
    .preservingProtoFieldNames();

// Proto field: user_name -> JSON field: user_name
// String json = preservingPrinter.print(message);

Handling Default Values

import akka.protobufv3.internal.util.JsonFormat;

// By default, fields with default values are omitted from JSON

// Include fields with default values
JsonFormat.Printer inclusivePrinter = JsonFormat.printer()
    .includingDefaultValueFields();

// This will include fields like:
// - Empty strings: "field": ""
// - Zero numbers: "field": 0  
// - False booleans: "field": false
// - Empty repeated fields: "field": []
// String jsonWithDefaults = inclusivePrinter.print(message);