{"id":20172965,"url":"https://github.com/marcono1234/serial-builder","last_synced_at":"2025-04-10T03:16:13.243Z","repository":{"id":42537646,"uuid":"445957812","full_name":"Marcono1234/serial-builder","owner":"Marcono1234","description":"Library for manually creating Java serialization data.","archived":false,"fork":false,"pushed_at":"2023-03-01T22:29:25.000Z","size":287,"stargazers_count":29,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T03:16:03.774Z","etag":null,"topics":["java-deserialization","java-serialization","javadeser","serialization"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Marcono1234.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2022-01-09T00:17:25.000Z","updated_at":"2025-02-07T13:34:14.000Z","dependencies_parsed_at":"2024-11-14T01:33:02.483Z","dependency_job_id":"8477a6f0-bc12-4948-871e-5d368545cc23","html_url":"https://github.com/Marcono1234/serial-builder","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marcono1234%2Fserial-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marcono1234%2Fserial-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marcono1234%2Fserial-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Marcono1234%2Fserial-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Marcono1234","download_url":"https://codeload.github.com/Marcono1234/serial-builder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248148245,"owners_count":21055548,"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","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":["java-deserialization","java-serialization","javadeser","serialization"],"created_at":"2024-11-14T01:32:58.635Z","updated_at":"2025-04-10T03:16:13.213Z","avatar_url":"https://github.com/Marcono1234.png","language":"Java","readme":":warning: This library is currently experimental, its behavior and API might change in the future.\n\n---\n\n# serial-builder\n\nLibrary for creating [Java serialization data](https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/index.html);\nmainly intended for research purposes. It is not recommended to use it in production as alternative for `ObjectOutputStream`.\n\nCompared to using Java's `ObjectOutputStream` this library has the following advantages:\n- It is not necessary to have the target classes on the classpath; it is possible to refer to classes only by their name.\n- It is possible to write arbitrary field values without having to access the internals of the target class with reflection.\n- It is possible to omit data or add additional serialization data which would normally not be written.\n\nThe entrypoints of this library are the classes [`SerialBuilder`](serial-builder/src/main/java/marcono1234/serialization/serialbuilder/SerialBuilder.java)\nand [`SimpleSerialBuilder`](serial-builder/src/main/java/marcono1234/serialization/serialbuilder/SimpleSerialBuilder.java).\nThe API structure of `SerialBuilder` is pretty close to the actual serialization data format. This allows low level\ncreation of serialization data, at the cost of verbose usage and reduced error checking. `SimpleSerialBuilder` operates\non a higher level, which makes its usage more concise and less error-prone. In most cases the API  offered by\n`SimpleSerialBuilder` should suffice.\n\nThe API offered by this library uses a 'fluent builder style', where all methods calls are chained after each other\n(with indentation to increase readability) until the end of the chain is reached, and the resulting serialization\ndata in the form of `byte[]` is returned. Using the API in any other way is not supported and might cause exceptions.\nIt is recommended to follow the IDE code completion suggestions while using the API, looking at the builder API\ninterfaces is most likely not that helpful.\n\n## Usage\nRequires Java 17 or newer\n\nCurrently this library is not published to Maven Central. You can either [build the project locally](#building)\nor you can [use JitPack as Maven repository](https://jitpack.io/#Marcono1234/serial-builder) serving this library.\n\nWhen using JitPack it is recommended to put the jitpack.io repository last in the list of declared repositories for\nbetter performance and to avoid pulling undesired dependencies from it. When using Gradle as build tool you should also\nuse [repository content filtering](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec:repository-content-filtering):\n```kotlin\nrepositories {\n    mavenCentral()\n    exclusiveContent {\n        forRepository {\n            maven {\n                url = uri(\"https://jitpack.io\")\n            }\n        }\n        filter {\n            // Only use JitPack for the `serial-builder` library\n            includeModule(\"com.github.Marcono1234.serial-builder\", \"serial-builder\")\n        }\n    }\n}\n```\n\n## API usage examples (`SimpleSerialBuilder`)\n\nNote: This project also supports generating Java code using this API to recreate existing serialization data, see the\n[code generation section below](#code-generation).\n\n### Class hierarchy\nLet's assume you have these two classes:\n```java\nclass ClassA implements Serializable {\n    @Serial\n    private static final long serialVersionUID = 1L;\n\n    public String a;\n}\n\nclass ClassB extends ClassA {\n    @Serial\n    private static final long serialVersionUID = 1L;\n\n    public String b;\n}\n```\n\nTo create serialization data for an instance of `ClassB`, you can use the API in the following way:\n```java\nbyte[] serialData = SimpleSerialBuilder.startSerializableObject()\n    // Start at the superclass\n    .beginClassData(ClassA.class)\n        .beginObjectField(\"a\", String.class)\n            .string(\"value-a\")\n        .endField()\n    .endClassData()\n    .beginClassData(ClassB.class)\n        .beginObjectField(\"b\", String.class)\n            .string(\"value-b\")\n        .endField()\n    .endClassData()\n.endObject();\n```\n\n### `writeObject` method\nLet's assume you have the following class with `writeObject` and `readObject` methods:\n```java\nclass ClassWithWriteObject implements Serializable {\n    @Serial\n    private static final long serialVersionUID = 1L;\n\n    public int i;\n    public String s;\n\n    public transient int i2;\n    public transient String s2;\n\n    @Serial\n    private void writeObject(ObjectOutputStream out) throws IOException {\n        out.defaultWriteObject();\n\n        out.writeInt(i2);\n        out.writeObject(s2);\n    }\n\n    @Serial\n    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {\n        in.defaultReadObject();\n\n        i2 = in.readInt();\n        s2 = (String) in.readObject();\n    }\n}\n```\n\nTo create serialization data for it, you can use the API in the following way:\n```java\nbyte[] serialData = SimpleSerialBuilder.startSerializableObject()\n    .beginClassData(ClassWithWriteObject.class)\n        // Represents the data written by the `defaultWriteObject()` call\n        .primitiveIntField(\"i\", 1)\n        .beginObjectField(\"s\", String.class)\n            .string(\"test\")\n        .endField()\n        // Represents the data manually written by `writeObject`\n        .writeObjectWith(writer -\u003e {\n            writer.writeInt(2);\n            writer.string(\"manually-written\");\n        })\n    .endClassData()\n.endObject();\n```\n\n### `Proxy` instances\nLet's assume you have the following `java.lang.reflect.InvocationHandler` implementation:\n```java\nclass CustomInvocationHandler implements InvocationHandler, Serializable {\n    @Serial\n    private static final long serialVersionUID = 1L;\n\n    public String result;\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) {\n        return result;\n    }\n}\n```\n\nTo create serialization data for a `java.lang.reflect.Proxy` instance which uses an instance of that invocation handler, you can use the\nAPI in the following way:\n```java\n// Starts a Proxy object which implements the Callable interface\nbyte[] serialData = SimpleSerialBuilder.startProxyObject(Callable.class)\n    .beginSerializableInvocationHandler()\n        .beginClassData(CustomInvocationHandler.class)\n            .beginObjectField(\"result\", String.class)\n                .string(\"custom-result\")\n            .endField()\n        .endClassData()\n    .endObject()\n.endProxyObject();\n```\n\n### Handles\nThe serialization protocol supports _handles_ which refer to a previously written instance. This API supports this\nfeature through the [`Handle`](serial-builder/src/main/java/marcono1234/serialization/serialbuilder/builder/api/Handle.java) class.\nFirst you create a new (unassigned) `Handle`, then you pass it to one of the builder methods with `Handle` parameter\nand afterwards you can use it to refer to the previously written object.\n\nThis library does not support using `Handle` in all cases where the serialization protocol supports it, but all\ninteresting cases should be covered (if you are missing support for a use case, feel free to create a GitHub issue).\n\nLet's assume you have the following class:\n\n```java\nclass Container implements Serializable {\n    @Serial\n    private static final long serialVersionUID = 1L;\n\n    public Serializable element;\n}\n```\n\nTo create serialization data for an instance of this class which contains itself, you can use the API in the following way:\n```java\n// First create a new unassigned handle\nHandle selfHandle = new Handle();\n// Then pass the handle here as argument to assign the written object to it\nbyte[] serialData = SimpleSerialBuilder.startSerializableObject(selfHandle)\n    .beginClassData(Container.class)\n        .beginObjectField(\"element\", Serializable.class)\n            // Finally, write a reference to the previously written object\n            .objectHandle(selfHandle)\n        .endField()\n    .endClassData()\n.endObject();\n```\n\n## Code generation\nEspecially when using this API for existing large serialization data, it can be cumbersome to manually write all the\nJava code to recreate the serialization data. Therefore, this project provides code generation functionality which,\nfor given serialization data, generates the corresponding API calls to recreate the serialization data (as close as\npossible). See the [README of the subproject](./serial-builder-codegen/README.md) for more information.\n\n## Project structure\nThis project is a multi-project Gradle build. It has the following subprojects:\n- [`serial-builder`](./serial-builder): Contains the source code of the builder API\n- [`serial-builder-codegen`](./serial-builder-codegen): Contains the source code for [code generation](#code-generation)\n\n## Building\nThis project uses Gradle for building; just run:\n```\n./gradlew build\n```\n\nIt is built against Java 17, but there is no need to manually install the correct JDK; Gradle's [toolchain](https://docs.gradle.org/current/userguide/toolchains.html)\nfeature automatically downloads the needed JDK. Some IDEs do not support toolchains yet, so you might have to\nconfigure them manually.\n\n## Similar / related projects\n- [NickstaDB's SerializationDumper](https://github.com/NickstaDB/SerializationDumper)\n- [frohoff's ysoserial](https://github.com/frohoff/ysoserial)\n- [Moritz Bechler's ruby-serialize](https://github.com/mb-syss/ruby-serialize)\n\n## License\nThis project [uses the MIT license](./LICENSE.txt); all contributions are implicitly under that license.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcono1234%2Fserial-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcono1234%2Fserial-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcono1234%2Fserial-builder/lists"}