{"id":27990728,"url":"https://github.com/lagrangedev/proto-anno","last_synced_at":"2025-10-30T10:41:41.598Z","repository":{"id":277671757,"uuid":"933161917","full_name":"LagrangeDev/proto-anno","owner":"LagrangeDev","description":"Annotation-based Protobuf Solution for Java","archived":false,"fork":false,"pushed_at":"2025-02-18T09:41:35.000Z","size":148,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-05T17:07:23.638Z","etag":null,"topics":["annotation","java","protobuf"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LagrangeDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-15T09:50:34.000Z","updated_at":"2025-02-18T09:32:45.000Z","dependencies_parsed_at":"2025-02-15T16:27:39.525Z","dependency_job_id":null,"html_url":"https://github.com/LagrangeDev/proto-anno","commit_stats":null,"previous_names":["wesley-young/proto-anno","lagrangedev/proto-anno"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/LagrangeDev/proto-anno","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LagrangeDev%2Fproto-anno","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LagrangeDev%2Fproto-anno/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LagrangeDev%2Fproto-anno/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LagrangeDev%2Fproto-anno/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LagrangeDev","download_url":"https://codeload.github.com/LagrangeDev/proto-anno/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LagrangeDev%2Fproto-anno/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281793832,"owners_count":26562614,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotation","java","protobuf"],"created_at":"2025-05-08T16:49:58.071Z","updated_at":"2025-10-30T10:41:41.562Z","avatar_url":"https://github.com/LagrangeDev.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# proto-anno\n\nAnnotation-based [Protocol Buffers](https://protobuf.dev/) solution for Java.\n\n## Overview\n\nIn C#, the protobuf-net library allows for annotating classes with attributes to define how they should be serialized. This library aims to provide a similar experience for Java developers.\n\n## Usage\n\n### Installation\n\nThis project uses [JitPack](https://jitpack.io/) to distribute the library. To add it to your project, follow the instructions below.\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd to Maven project\u003c/summary\u003e\n\nAdd the JitPack repository to your `pom.xml` file:\n```xml\n\u003crepositories\u003e\n    \u003crepository\u003e\n        \u003cid\u003eJitPack\u003c/id\u003e\n        \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n    \u003c/repository\u003e\n\u003c/repositories\u003e\n```\n\nThen add the dependency:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.LagrangeDev\u003c/groupId\u003e\n    \u003cartifactId\u003eproto-anno\u003c/artifactId\u003e\n    \u003cversion\u003e0.2.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd to Gradle project\u003c/summary\u003e\n\nAdd the JitPack repository and dependency to your `build.gradle` file:\n```groovy\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n\ndependencies {\n    implementation 'com.github.LagrangeDev:proto-anno:0.2.1'\n}\n```\n\nFor `build.gradle.kts`:\n```kotlin\nrepositories {\n    maven(\"https://jitpack.io\")\n}\n\ndependencies {\n    implementation(\"com.github.LagrangeDev:proto-anno:0.2.1\")\n}\n```\n\u003c/details\u003e\n\nSee the [JitPack documentation](https://docs.jitpack.io/) for more.\n\n### Defining a Message\n\nFirst define a class that extends `ProtoMessage`. Then annotate fields with `@ProtoField`.\n```java\npublic class Person extends ProtoMessage {\n    @ProtoField(1)\n    public String name;\n    \n    @ProtoField(2)\n    public int id;\n    \n    @ProtoField(3)\n    public String email;\n}\n```\nNote that all the annotated fields should be public because the library uses reflection to access them.\n\nYou can instantiate a `Person` object like this:\n```java\nvoid doSomething() {\n    Person person = new Person();\n    person.name = \"Alice\";\n    person.id = 123;\n    person.email = \"someone@example.com\";\n}\n```\n\nTo serialize the object to a byte array:\n```java\nvar serializer = ProtobufSerializer.of(Person.class);\nbyte[] bytes = serializer.serialize(person);\n```\n\nAlso, to deserialize a byte array to an object:\n```java\nvar deserializer = ProtobufDeserializer.of(Person.class);\nPerson deserializedPerson = deserializer.deserialize(bytes);\n```\n\n### Constructors\n\nIf you want to add a constructor with arguments to the class, **you should also declare a no-argument constructor in the class**. The library will use this constructor to instantiate the object when deserializing. Otherwise, a `NoSuchMethodException` will be thrown. So you can declare the `Person` class like this:\n```java\npublic class Person extends ProtoMessage {\n    @ProtoField(1)\n    public String name;\n    \n    @ProtoField(2)\n    public int id;\n    \n    @ProtoField(3)\n    public String email;\n    \n    // proto-anno needs this to deserialize\n    public Person() {\n    }\n    \n    public Person(String name, int id, String email) {\n        this.name = name;\n        this.id = id;\n        this.email = email;\n    }\n}\n```\n\nOnly under one specific condition can you omit the no-argument constructor while preserving constructors with arguments. That is when you do not need to deserialize the object. For example, you only need to serialize the object and send it to another service.\n\n### Type Mapping\n\nAll the [scalar value types](https://protobuf.dev/programming-guides/proto3/#scalar) mentioned in the official protobuf documentation are supported. The types can be either inferred from the field type or explicitly specified by annotating the field with `@TypeMappedTo`. `int` and `long` can be mapped to multiple protobuf types.\n\n| Java      | Inferred  | Supported                                          |\n|-----------|-----------|----------------------------------------------------|\n| `boolean` | `bool`    | `bool`                                             |\n| `int`     | `int32`   | `int32`, `uint32`, `sint32`, `fixed32`, `sfixed32` |\n| `long`    | `int64`   | `int64`, `uint64`, `sint64`, `fixed64`, `sfixed64` |\n| `float`   | `float`   | `float`                                            |\n| `double`  | `double`  | `double`                                           |\n| `String`  | `string`  | `string`                                           |\n| `byte[]`  | `bytes`   | `bytes`                                            |\n\n### Explicitly \u0026 Implicitly Optional Fields\n\n\"Explicitly optional\" means that if not present in serialized data when deserializing, the field will be set to `null` in the output object. In contrast, \"implicitly optional\" means that the field must be non-nullish in the deserialized data. Chances are that the field is not present in the **serialized data**, and the field will be set to the [built-in default value](#default-values) of the field type.\n\nFor a nested implicitly optional field, the default value of the field type will be used. For a nested explicitly optional field, the field will be set to `null`. \n\n\u003cdetails\u003e\n\u003csummary\u003eWhy \"implicitly optional\" instead of \"required\"?\u003c/summary\u003e\n\n\"Implicitly optional\" is not equal to \"required\". A \"required\" field must be present in the **serialized data**. If not, the deserialization process will **throw an exception**. This feature is so annoying that it is deprecated in proto3. In proto3, all the fields are implicitly optional by default. proto-anno does not support \"required\" fields.\n\u003c/details\u003e\n\n`org.jetbrains:annotations` provides a set of annotations to indicate nullability. By default, all fields are implicitly optional. You can annotate a non-primitive field with `@Nullable` to make it explicitly optional, so that the field will be set to `null` instead of a non-nullish value if it is not present in the serialized data.\n\n`@NotNull`-annotated field will not be recognized as a required field. Still, you can use it to indicate that the field should not be `null` under any circumstances, and your IDE will give you a warning if you do not initialize a default value for the field, or if you try to assign `null` to the field.\n\n### Default Values\n\nHere is a simple table that explains the built-in default values of implicitly optional and explicitly optional fields:\n\n| Field Type | Implicitly Optional | Explicitly Optional |\n|------------|---------------------|---------------------|\n| `boolean`  | `false`             | Not supported       |\n| `int`      | `0`                 | Not supported       |\n| `long`     | `0`                 | Not supported       |\n| `float`    | `0.0f`              | Not supported       |\n| `double`   | `0.0`               | Not supported       |\n| `String`   | `\"\"`                | `null`              |\n| `byte[]`   | `new byte[0]`       | `null`              |\n\nYou can overwrite the built-in default values by setting the field value directly upon declaration or in the constructor. Here is an example struct with explicitly optional fields, and implicitly optional fields with or without custom default values:\n```java\npublic class Person extends ProtoMessage {\n    @ProtoField(1)\n    public String name = \"Alice\";   // Default value set upon declaration\n    \n    @ProtoField(2)\n    public int id;                  // Default value set in the constructor\n    \n    @ProtoField(3)\n    @Nullable\n    public String email;            // Will be set to null if not present in the serialized data\n    \n    @ProtoField(4)\n    public List\u003cString\u003e phones;     // Will be assigned an empty list if not present in the serialized data\n    \n    public Person() {\n        id = 123;                   // Sets the default value of the field\n    }\n}\n```\n\n### Repeated Fields\n\n[fastutil](https://fastutil.di.unimi.it/) provides a set of fast and compact implementations of type-specific maps and sets. proto-anno uses `IntList`, `LongList`, `FloatList`, `DoubleList` and `BooleanList` in fastutil to store repeated primitive values, and `java.util.List` to store repeated string, byte array and message values. You cannot use `List` to store repeated primitive values, vice versa. \n\nThe annotation `@TypeMappedTo` also applies to repeated fields. For example:\n```java\npublic class Person extends ProtoMessage {\n    @ProtoField(1)\n    public List\u003cString\u003e names;\n    \n    @ProtoField(2)\n    @TypeMappedTo(FieldType.UINT32)\n    public IntList ids;             // manually specified as uint32\n    \n    @ProtoField(3)\n    public DoubleList scores;       // automatically inferred as double\n    \n    @ProtoField(4)\n    public List\u003cPerson\u003e friends;\n}\n```\n\n### Packed Encoding\n\nAs is mentioned in the [official documentation](https://protobuf.dev/programming-guides/encoding/#packed), it is recommended to use packed encoding for repeated primitive fields, and proto3 uses packed encoding by default. proto-anno also uses packed encoding by default. You can disable packed encoding by annotating the field with `@DisablePacking`.\n\nThis annotation only applies to the **encoding** process of **repeated primitive fields**. When deserializing, proto-anno will automatically detect whether the field is packed or not. Also, when it is used on repeated non-primitive fields, it will be ignored.\n\n### Unsigned Integers\n\nJava does not have unsigned integer types, and you can get around this by API provided in `java.lang.Integer` and `java.lang.Long`. For example:\n```java\npublic class UnsignedTest extends ProtoMessage {\n    @ProtoField(1)\n    @TypeMappedTo(FieldType.UINT32)\n    public int bigNumber;\n    \n    @ProtoField(2)\n    @TypeMappedTo(FieldType.UINT64)\n    public long evenBiggerNumber;\n}\n\nUnsignedTest test = ProtobufDeserializer.of(UnsignedTest.class).deserialize(bytes);\nlong bigNumber = Integer.toUnsignedLong(test.bigNumber);\nString evenBiggerNumber = Long.toUnsignedString(test.evenBiggerNumber);\n```\n\n### Use with Lombok\n\n[Project Lombok](https://projectlombok.org/) is a library that helps reduce boilerplate code in Java. You can use it with proto-anno to further simplify your code.\n\nThe example in the [test folder](/src/test/java/org/lagrangecore/proto/test/GeneralTestMessage.java) uses the Lombok annotation `@Builder`. When you are using `@Builder`, you should also use the annotation `@NoArgsConstructor` to generate a no-argument constructor. And to avoid compilation errors, you should also add an `@AllArgsConstructor` to generate a constructor with all the fields, which is used by Lombok to generate the `build()` method. So in total you need at least three annotations: `@Builder`, `@NoArgsConstructor` and `@AllArgsConstructor`.\n\n## Limitations\n\nThe following features are not supported:\n- `GROUP` wire type (deprecated)\n- Required fields (deprecated in proto3)\n- Optional fields for primitive types\n- [Enumerations](https://protobuf.dev/programming-guides/proto3/#enum)\n- [Extensions](https://protobuf.dev/programming-guides/proto2/#extensions)\n- [Any](https://protobuf.dev/programming-guides/proto3/#any)\n- [Oneof](https://protobuf.dev/programming-guides/proto3/#oneof)\n\n[Maps](https://protobuf.dev/programming-guides/proto3/#maps) are not supported, but you can refer to the [Backward Compatibility](https://protobuf.dev/programming-guides/proto3/#backwards) section in the official documentation to see how to represent maps using repeated fields.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flagrangedev%2Fproto-anno","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flagrangedev%2Fproto-anno","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flagrangedev%2Fproto-anno/lists"}