Skip to content

Instantly share code, notes, and snippets.

@devinrsmith
Created October 19, 2023 19:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devinrsmith/74e0a9b230f6bb3975beebed3ec8c253 to your computer and use it in GitHub Desktop.
Save devinrsmith/74e0a9b230f6bb3975beebed3ec8c253 to your computer and use it in GitHub Desktop.
Cap'n Proto code generation and reflection for java

Cap’n Proto to Java

Note: this guide assumes Fedora, steps may be different for other OSes.

Install capnproto

sudo dnf install capnproto

Install capnproto-java

sudo dnf install gcc-c++ capnproto-devel
cd /tmp
git clone --depth 1 --branch v0.1.16 https://github.com/capnproto/capnproto-java.git
cd /tmp/capnproto-java
make
cd /tmp
PATH="$PATH:/tmp/capnproto-java"

Compiling schema to Java

mkdir foo
capnp compile \
    -I/tmp/capnproto-java/compiler/src/main/schema \
    -ojava:foo \
    bar.capnp

produces /tmp/foo/Baz.java

Refering to code-generation in Java

Classpath needs:

  • implementation 'org.capnproto:runtime:0.1.16'
  • /tmp/foo/Baz.java

Can refer to com.example.Baz (or, whatever namespace bar.capnp defines) in code.

Schema reading in Java

See capnproto-java/issues/136 for context.

Create binary schema

capnp compile \
    -I/tmp/capnproto-java/compiler/src/main/schema \
    -o/bin/cat \
    bar.capnp > bar.capnp.bin

Create meta-schema in Java

Need to apply patch to official schema.capnp for Java support.

cd /tmp
# Note: choosing version that is the same package manager installed. See note later.
git clone --depth 1 --branch v0.10.3 https://github.com/capnproto/capnproto.git
cd /tmp/capnproto
git apply <<'EOF'
diff --git a/c++/src/capnp/schema.capnp b/c++/src/capnp/schema.capnp
index a47c151..78d0128 100644
--- a/c++/src/capnp/schema.capnp
+++ b/c++/src/capnp/schema.capnp
@@ -20,10 +20,14 @@
 # THE SOFTWARE.
 
 using Cxx = import "/capnp/c++.capnp";
+using Java = import "/capnp/java.capnp";
 
 @0xa93fc509624c72d9;
 $Cxx.namespace("capnp::schema");
 
+$Java.package("capnp.schema");
+$Java.outerClassname("Schema");
+
 using Id = UInt64;
 # The globally-unique ID of a file, type, or annotation.
 
EOF
cd /tmp
mkdir /tmp/capnp-schema
    
# I'm not sure if there's potential for incompatible schemas between checked out
# capnproto and capnproto-devel. Choosing to explicitly reference checkoud out
# version (not sure if it actually applies, interefers, or is exactly the same).
# It may be worthwhile doing the whole pipeline without capnproto-devel and 
# including capnproto explicitly.
capnp compile \
    -I/tmp/capnproto/c++/src/ \
    -I/tmp/capnproto-java/compiler/src/main/schema \
    -ojava:capnp-schema \
    /tmp/capnproto/c++/src/capnp/schema.capnp

produces /tmp/capnp-schema/capnproto/c++/src/capnp/Schema.java

Read

Classpath needs:

  • implementation 'org.capnproto:runtime:0.1.16'
  • /tmp/capnp-schema/capnproto/c++/src/capnp/Schema.java
import capnp.schema.Schema;
import org.capnproto.MessageReader;
import org.capnproto.Serialize;

import java.io.IOException;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;

public class ReadBinarySchema {

    public void codeGenerationRequest() throws IOException {
        final Path path = Path.of("bar.capnp.bin");
        final MessageReader reader;
        try (final SeekableByteChannel binarySchema = Files.newByteChannel(path)) {
            reader = Serialize.read(binarySchema);
        }
        final Schema.CodeGeneratorRequest.Reader codeGenerationRequest = reader.getRoot(Schema.CodeGeneratorRequest.factory);
        for (Schema.Node.Reader node : codeGenerationRequest.getNodes()) {
            System.out.println(node.getDisplayName());
        }
        // Further implementation left to reader
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment