{"id":15944216,"url":"https://github.com/dimasmith/parameter-object","last_synced_at":"2025-04-03T21:43:27.233Z","repository":{"id":75302656,"uuid":"198478165","full_name":"dimasmith/parameter-object","owner":"dimasmith","description":"Example of java source annotation processor ","archived":false,"fork":false,"pushed_at":"2019-10-23T19:27:16.000Z","size":93,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-02-09T09:42:50.172Z","etag":null,"topics":["annotation-processor","java"],"latest_commit_sha":null,"homepage":null,"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/dimasmith.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}},"created_at":"2019-07-23T17:28:42.000Z","updated_at":"2019-10-23T19:27:17.000Z","dependencies_parsed_at":"2023-02-28T05:16:14.902Z","dependency_job_id":null,"html_url":"https://github.com/dimasmith/parameter-object","commit_stats":{"total_commits":28,"total_committers":1,"mean_commits":28.0,"dds":0.0,"last_synced_commit":"e3a4e5321091c5369c1a22534f964aaa8854fd07"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimasmith%2Fparameter-object","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimasmith%2Fparameter-object/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimasmith%2Fparameter-object/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimasmith%2Fparameter-object/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dimasmith","download_url":"https://codeload.github.com/dimasmith/parameter-object/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247085982,"owners_count":20881158,"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":["annotation-processor","java"],"created_at":"2024-10-07T08:21:39.289Z","updated_at":"2025-04-03T21:43:27.212Z","avatar_url":"https://github.com/dimasmith.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Parameter Object Generator\n==========================\n\n[![Build Status](https://travis-ci.org/dimasmith/parameter-object.svg?branch=develop)](https://travis-ci.org/dimasmith/parameter-object)\n\n---\nAnnotation and annotation processor to extract parameter objects from methods.\n\n## Example\n\nLet's imagine we have a service class and we want to do something with methods of this service. \nFor example write an audit trail.\nThe `@Audit` annotation tells auditing system to use certain processor class to create audit message.\n\n```java\nclass UserService {\n    \n    @Audit(processor = CreateUserAuditor.class)\n    User createUser(String firstName, String lastName, List\u003cOrder\u003e orders) {\n        // do some work\n    }\n}\n```\n\nAudit processors have an interface like this\n\n```java\ninterface AuditProcessor {\n    \n    AuditMessage beforeMethod(Audit auditAnnotation, Map\u003cString, Object\u003e parameters);\n}\n```\n\nMethod parameters passed to audit processors as a map of named objects.\nThis solution is brittle - once we rename parameter in an audited method an error will occur somewhere in runtime.\nBesides we need to explicitly cast types when processing parameters. E.g.\n\n```java\nclass CreateUserAuditor implements AuditProcessor {\n    AuditMessage beforeMethod(Audit auditAnnotation, Map\u003cString, Object\u003e parameters) {\n        List\u003cOrder\u003e orders = (List\u003cOrder\u003e) parameters.get(\"orders\");\n        return AuditMessage.builder()\n            .message(\"Creating user\")\n            .addAttribute(\"orders\", orders.size())\n            .build();\n    }\n}\n```\n\nImagine we cannot change the signature of `AuditProcessor` and get rid of parameters map or pass annotated method down.\nOne possibility to mitigate it is to create a Parameter Object from all method parameters.\nAdd factory method to create it from the map of named objects and use wrapped map.\n\n```java\nclass CreateUserParameters {\n    private final String firstName;\n    private final String lastName;\n    private final List\u003cOrder\u003e orders;\n    \n    CreateUserParameters(Map\u003cString, Object\u003e parameters) {\n        firstName = (String) parameters.get(\"firstName\");\n        lastName = (String) parameters.get(\"lastName\");\n        orders = (Collections).unmodifiableList((List\u003cOrder\u003e)parameters.get(\"orders\"));\n    }    \n    \n    // getters\n}\n```  \n\nUsing this instead of operating on map will make code in audit processor cleaner\n \n ```java\nclass CreateUserAuditor implements AuditProcessor {\n   AuditMessage beforeMethod(Audit auditAnnotation, Map\u003cString, Object\u003e parameters) {\n       CreateUserParameters args = new CreateUserParameters(parameters);\n       return AuditMessage.builder()\n           .message(\"Creating user\")\n           .addAttribute(\"orders\", args.getOrders().size())\n           .addAttribute(\"name\", args.getLastName() + \" \" + args.getFirstName())\n           .build();\n   }\n}\n ```\n \n But the issue with renaming parameters is still there. \n It may go out of sync in parameter object as well.\n But what if instead writing such parameter object we can generate it on compilation?\n No writing boilerplate code is necessary.\n Also reading from map does not go out of sync neither in names, nor in types.\n \n Parameter object adds an annotation `@ParameterObject` and compiler processor to generate classes with parameters.\n \n What we'll have is:\n \n ```java\n class UserService {\n     \n     @Audit(processor = CreateUserAuditor.class)\n     @ParameterObject // processor generates parameter object from signature\n     User createUser(String firstName, String lastName, List\u003cOrder\u003e orders) {\n         // do some work\n     }\n }\n ```\n \n Parameter objects will compile before the rest of the code, so it is possible to use it right away.\n \n ## Project structure\n \n The project contains two subprojects\n \n * `annotation` - containing an `@ParameterObject` annotation;\n * `annotation-processor` - an annotation processor for the compiler;\n * `example` - project with usage examples and tests;\n \n ## How to use it\n \n ### With maven\n \n Add annotation processor as optional dependency to the project dependency list:\n \n ```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.anatolich.parameterobject\u003c/groupId\u003e\n  \u003cartifactId\u003eannotation-processor\u003c/artifactId\u003e\n  \u003cversion\u003e0.1.0-SNAPSHOT\u003c/version\u003e\n  \u003coptional\u003etrue\u003c/optional\u003e\n\u003c/dependency\u003e\n ``` \n \n Add an annotation module to the project dependency list:\n  ```xml\n \u003cdependency\u003e\n   \u003cgroupId\u003enet.anatolich.parameterobject\u003c/groupId\u003e\n   \u003cartifactId\u003eannotation\u003c/artifactId\u003e\n   \u003cversion\u003e0.1.0-SNAPSHOT\u003c/version\u003e\n \u003c/dependency\u003e\n  ``` \n\nAnnotate methods of your classes with `@ParameterObject` annotation.\n\n## Features\n\n### Customize parameter object class names\n\nBy default the parameter object will be named by the pattern: `\u003cClassName\u003e\u003cMethodName\u003eParameters`.\nIt will reside in the same package as the class with an annotated method.\n\nTo change name and/or package use:\n\n```java\n@ParameterObject(packageName=\"my.parameters\", className=\"AwesomeParameters\")\nvoid awesomeMethod(String message) {}\n```\n\nWhen any of the attributes missing the default strategy is applied to missing component.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimasmith%2Fparameter-object","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdimasmith%2Fparameter-object","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimasmith%2Fparameter-object/lists"}