{"id":36705436,"url":"https://github.com/pellse/decorator","last_synced_at":"2026-01-12T11:42:14.822Z","repository":{"id":57734463,"uuid":"75694793","full_name":"pellse/decorator","owner":"pellse","description":"A library that emulates in Java the Scala's Stackable Trait Pattern by implementing the decorator pattern at runtime through class composition instead of only through object composition.","archived":false,"fork":false,"pushed_at":"2018-12-08T05:23:48.000Z","size":131,"stargazers_count":1,"open_issues_count":7,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-17T14:08:24.745Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pellse.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}},"created_at":"2016-12-06T04:35:13.000Z","updated_at":"2024-03-16T11:11:29.000Z","dependencies_parsed_at":"2022-08-24T03:21:31.185Z","dependency_job_id":null,"html_url":"https://github.com/pellse/decorator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pellse/decorator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellse%2Fdecorator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellse%2Fdecorator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellse%2Fdecorator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellse%2Fdecorator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pellse","download_url":"https://codeload.github.com/pellse/decorator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellse%2Fdecorator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-01-12T11:42:14.772Z","updated_at":"2026-01-12T11:42:14.816Z","avatar_url":"https://github.com/pellse.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Decorator\n\nA library that emulates in Java the Scala's Stackable Trait Pattern by implementing the decorator pattern at runtime through class composition instead of only through object composition. The goal is to allow the creation of very small partial components (i.e. partial implementation of interfaces or abstract classes) that can be dynamically assembled into full components at runtime.\n\nThe library can also be used to mix and chain aop style decorators with partial components, and also as a more elegant way to chain fully implemented or existing decorators.\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.pellse/decorator/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.pellse/decorator)\n\n## Usage Examples\n\nThis example shows how to create a component by extending an interface and only implement the necessary methods, the framework will  automatically generate the unimplemented pass through delegate methods. The framework will use the provided delegate method signature as an injection point for the delegate class instance to which we should forward methods to:\n```java\nimport java.util.Collection;\nimport java.util.List;\n\nimport com.esotericsoftware.kryo.Kryo;\n\npublic interface SafeList\u003cE\u003e extends List\u003cE\u003e {\n\t\n\tstatic Kryo kryo = new Kryo();\n\t\n\t// The framework will automatically implement this method.\n\t// The return type is inspected so the actual method name doesn't matter.\n\tList\u003cE\u003e getDelegate();\n\n\t@Override\n\tdefault boolean add(E e) {\n\t\treturn getDelegate().add(clone(e));\n\t}\n\t\n\t@Override\n\tdefault void add(int index, E e) {\n\t\tgetDelegate().add(index, clone(e));\n\t}\n\n\t@Override\n\tdefault boolean addAll(Collection\u003c? extends E\u003e c) {\n\t\treturn getDelegate().addAll(c.stream().map(SafeList::clone).collect(toList()));\n\t}\n\n\t@Override\n\tdefault boolean addAll(int index, Collection\u003c? extends E\u003e c) {\n\t\treturn getDelegate().addAll(index, c.stream().map(SafeList::clone).collect(toList()));\n\t}\n\n\t@Override\n\tdefault E set(int index, E e) {\n\t\treturn getDelegate().set(index, clone(e));\n\t}\n\n\tstatic \u003cE\u003e E clone(E obj) {\n\t\treturn kryo.copy(obj);\n\t}\n}\n\nSafeList\u003cString\u003e decoratorList = Decorator.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(SafeList.class)\n\t.make();\n```\n\nIt is also possible to create a partial component by providing an abstract class that implement only the methods that need to be overriden (some methods were removed for brevity), the framework will use the provided constructor to inject the appropriate delegate:\n```java\npublic abstract class DirtyList\u003cE\u003e implements List\u003cE\u003e {\n\n\tprivate List\u003cE\u003e delegate;\n\n\tprivate boolean isDirty = false;\n\n\tpublic DirtyList(List\u003cE\u003e delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\tpublic boolean isDirty() {\n\t\treturn isDirty;\n\t}\n\n\t@Override\n\tpublic boolean add(E e) {\n\t\tisDirty = true;\n\t\treturn delegate.add(e);\n\t}\n\n\t@Override\n\tpublic boolean remove(Object o) {\n\t\tisDirty = true;\n\t\treturn delegate.remove(o);\n\t}\n\n\t@Override\n\tpublic boolean addAll(Collection\u003c? extends E\u003e c) {\n\t\tisDirty = true;\n\t\treturn delegate.addAll(c);\n\t}\n}\n\nDirtyList\u003cString\u003e dirtyList = Decorator.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(SafeList.class)\n\t.with(DirtyList.class)\n\t.make();\n```\n\nThe `@Inject` annotation is also supported:\n```java\npublic abstract class DirtyList\u003cE\u003e implements List\u003cE\u003e {\n\n\t@Inject\n\tprivate List\u003cE\u003e delegate;\n\n\tprivate boolean isDirty = false;\n\n\tpublic boolean isDirty() {\n\t\treturn isDirty;\n\t}\n\n\t@Override\n\tpublic boolean add(E e) {\n\t\tisDirty = true;\n\t\treturn delegate.add(e);\n\t}\n\n\t...\n}\n```\n\nPartial components can also have non zero argument constructors:\n```java\npublic abstract class BoundedList\u003cE\u003e implements List\u003cE\u003e {\n\n\tprivate final int maxNbItems;\n\n\tprotected abstract List\u003cE\u003e getDelegateList();\n\n\tpublic BoundedList(int maxNbItems) {\n\t\tthis.maxNbItems = maxNbItems;\n\t}\n\n\t@Override\n\tpublic boolean add(E e) {\n\t\tcheckSize(1);\n\t\treturn getDelegateList().add(e);\n\t}\n\t\n\t// addAll(), remove(), etc. were not implemented here for brevity\n\n\tprotected void checkSize(int addCount) {\n\t\tif (getDelegateList().size() + addCount \u003e= maxNbItems)\n\t\t\tthrow new IllegalStateException(\"Size of list greater than maxNbItems (\" + maxNbItems + \")\");\n\t}\n}\n\nDirtyList\u003cString\u003e dirtyList = DecoratorBuilder.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(SafeList.class)\n\t.with(BoundedList.class)\n\t\t.params(50)\n\t\t.paramTypes(int.class)\n\t.with(DirtyList.class)\n\t.make();\n```\n\nWe can also chain partial components with existing decorators that fully implement the specified interface:\n```java\nDirtyList\u003cString\u003e dirtyList = Decorator.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(delegate -\u003e Collections.synchronizedList(delegate))\n\t.with(SafeList.class)\n\t.with(DirtyList.class)\n\t.make();\n```\n\nThis is another example using the fluent api as syntactic sugar to chain already fully implemented decorators instead of embedding layers of constructor parameter calls:\n```java\nDataInputStream din = DecoratorBuilder.of(new FileInputStream(\"data.txt\"), InputStream.class)\n\t.with(delegate -\u003e new BufferedInputStream(delegate, 50))\n\t.with(delegate -\u003e new DataInputStream(delegate))\n\t.make();\n```\nWhich is the equivalent of:\n```java\nDataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(\"data.txt\"), 50));\n```\n\nAnd we can mix dynamic proxy components:\n```java\nDirtyList\u003cString\u003e dirtyList = DecoratorBuilder.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(SafeList.class)\n\t.with(BoundedList.class)\n\t\t.params(50)\n\t\t.paramTypes(int.class)\n\t.with((delegate, method, args) -\u003e method.invoke(delegate, args))\n\t.with(DirtyList.class)\n\t.make();\n```\n\n```java\npublic interface IDirtyList\u003cE\u003e extends List\u003cE\u003e {\n\tboolean isDirty();\n}\n\npublic class DirtyListInvocationHandler\u003cT\u003e implements DelegateInvocationHandler\u003cT\u003e {\n\n\tprivate boolean isDirty;\n\n\t@Override\n\tpublic Object invoke(T delegate, Method method, Object[] args) throws Throwable {\n\t\tif (method.getName().equals(\"isDirty\"))\n\t\t\treturn isDirty;\n\t\t\t\n\t\tif (Stream.of(\"add\", \"remove\", \"set\", \"clear\", \"retain\").anyMatch(s -\u003e method.getName().startsWith(s)))\n\t\t\tisDirty = true;\n\n\t\treturn method.invoke(delegate, args);\n\t}\n}\n\nIDirtyList\u003cEmptyClass\u003e dirtyList = DecoratorBuilder.of(new ArrayList\u003c\u003e(), List.class)\n\t.with(SafeList.class)\n\t.with(new DirtyListInvocationHandler\u003c\u003e())\n\t\t.as(IDirtyList.class)\n\t.make();\n```\n\n## License\n\nCopyright 2017 Sebastien Pelletier\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpellse%2Fdecorator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpellse%2Fdecorator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpellse%2Fdecorator/lists"}