{"id":23792490,"url":"https://github.com/se2p/perfumator","last_synced_at":"2026-03-01T11:31:33.466Z","repository":{"id":259718908,"uuid":"803637812","full_name":"se2p/perfumator","owner":"se2p","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-15T13:39:08.000Z","size":553,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-24T23:15:28.453Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/se2p.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":"2024-05-21T05:36:18.000Z","updated_at":"2025-05-15T13:35:16.000Z","dependencies_parsed_at":"2024-10-27T15:21:18.970Z","dependency_job_id":"186237fd-54ab-4772-9bdf-226953d63be5","html_url":"https://github.com/se2p/perfumator","commit_stats":null,"previous_names":["se2p/perfumator"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/se2p/perfumator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se2p%2Fperfumator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se2p%2Fperfumator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se2p%2Fperfumator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se2p%2Fperfumator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/se2p","download_url":"https://codeload.github.com/se2p/perfumator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se2p%2Fperfumator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29968452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T10:55:55.490Z","status":"ssl_error","status_checked_at":"2026-03-01T10:55:55.175Z","response_time":124,"last_error":"SSL_read: 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":"2025-01-01T18:35:18.117Z","updated_at":"2026-03-01T11:31:33.449Z","avatar_url":"https://github.com/se2p.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The Perfumator\n\nRepository for the \"Perfumator\" project for Java. A small command line application to detect certain\nCode Perfumes in Java source code.\n\nThis project is part of the **Perfuming Java for learners: an adoption of Code Perfumes for Java** bachelor thesis by Jakob Silbereisen\nat the Chair of Software Engineering II (University of Passau).\n\n## How to build the Perfumator\n\nBuild requirements:\n\n- JDK 17\n- Apache Maven build tool (last built with version 3.9.1)\n\nThe application is packaged as an executable JAR with dependencies. For packaging, navigate to the project folder in a\nterminal and execute:\n`mvn clean package`.\n\nThis creates the **target/** directory, where you can find the executable JAR with dependencies, named like\n_perfumator-java-X.Y.Z-jar-with-dependencies.jar_, where _X.Y.Z_ is the version.\n\nTo execute all tests (including integration tests), run `mvn verify`.\n\n## Executing the Perfumator\n\nTo start the tool from the command line, execute\n\n`java -jar ARTIFACT -i INPUT_PATH -o OUTPUT_PATH [additional options ...]`\n\nin the terminal,\nwhere _ARTIFACT_ is the path to the executable, packaged with dependencies, Perfumator-JAR.\nFor an overview over all available command line arguments/options, use the `-h` or `--help` option (might be more up-to-date than this description).\n\nThe following arguments **must** be provided for analysis execution (not if `-h` or `--help` is given):\n\n- `-i INPUT_PATH` or `--input INPUT_PATH`: Path to the directory/Java source file, which should be taken as the root directory for analysis (or be directly analysed if it is a single file). Will be recursively scanned for Java Source files. Notice that, if the project directory to analyse follows the typical Maven/Gradle directory structure, all Java source files that are placed in (a subdirectory of) **src/main/resources** or **src/test/resources** will be ignored in the analysis.\n- `-o OUTPUT_PATH` or `--output-dir OUTPUT_PATH`: Path to an **empty** directory, where the analysis output should be stored. The standard analysis output (here: JSON format) consists of a file called _summary.json_, which presents a concise overview over all Perfumes that were analysed and the amount of detections, and a file called **detections.json**, which lists ALL instances of detections of any Perfume. There might be multiple **detection** files produced, if the amount of detections is higher than the batch size for one file. Then, the detection-files will be suffixed with ongoing numbers, starting with 1.\n\nAdditional, optional arguments:\n\n- `-h` or `--help`: Prints the help-overview over all available commands, then terminates the application, no matter which other arguments are given.\n- `-f FORMAT` or `--format`: Sets the format for the output. **Currently, only JSON is supported.**\n- `-l LANGUAGE_TAG` or `--language`: Sets the _preferred_ language for the tool. This means, if available, all log messages/error messages/output resources/perfumes have the given language. If any resource is not available in that language, the English version is used as a fallback. Currently, the only supported languages are English and German, including Perfume and CLI resources.\n- `-d \"path;path2;...\"` or `--dependencies`: A list of dependencies for the analysis. A dependency can be JAR or simply a source root directory of a project. If you want to only analyse a single file, you should at least provide the project's source root (if the file is part of a project) as a dependency, for some context. If required external dependencies are missing, some Perfumes might not be detected under certain circumstances/at all.\n- `-b BATCH_SIZE` or `--batch-size`: Sets the batch size (size for the listings of detections) for the serialized output, default: 10000. If you encounter an OOM error when running the analysis, lowering the batch size might help.\n\n## API\n\n### Main engine\n\nThe `de.jsilbereisen.perfumator.engine.PerfumeDetectionEngine` class is responsible for running the analysis.\nAn instance can be created via its inner class `Builder`, which offers the default configuration with a zero-arguments constructor.\n\nWhen using the default configuration, all Perfumes definitions are\nloaded from the default location (see the later sections for more information on the default locations) with the default resource language (English).\nAlso, a standard **JavaParser** is initialized, with its _Java language level set to 17_ (highest supported language level).\n\nBy implementing the `DetectionEngine` interface, the engine offers two main methods for the analysis: `detect` and `detectAndSerialize`.\n`detect` runs the analysis and returns a list of detections, while `detectAndSerialize` returns `void` but serializes the analysis results.\nFor huge projects, `detect` might cause an `OutOfMemoryError` (OOM), because it holds all detections in memory to return them,\nwhile `detectAndSerialize` allows specification of a batch-size, after which the current list of detections in memory is flushed\nto the output directory, to avoid OOMs.\n\n**Note** that if the directory to analyse follows a Maven/Gradle project structure (has sources in `src/main/java`,\nresources in `src/main/resources`, and equivalent directories for the unit tests), then all Java source files that are\nunder the usual resources-directories are **ignored** by the engine for the analysis.\n\n### Useful utility\n\nThe `de.jsilbereisen.perfumator.util.JsonDeserializationUtil` class offers utility methods for deserializing analysis results that\nare produced by the application (perfume listings, summary).\n\nIf you want to write unit tests, e.g. for own Perfumes, the `src/test/java/test` directory contains for example abstract classes\nthat you can inherit from for common kinds of tests, as well as other test-related utility. \n\n## Adding a new Code Perfume ...\n\n### ... with the default configurations\n\nThe Perfumator auto-detects Code Perfume definitions (JSON) in the `src/main/resources/de/jsilbereisen/perfumator/data/perfumes`\ndirectory. It will look to load a Perfume instance with this information into memory, and also instantiate and link the associated Detector class.\nThe loaded Perfumes and Detectors and their links are kept in a `PerfumeRegistry` during runtime.\n\nIf you wish to add a new Code Perfume to the application, first start off by adding the JSON definition of your new Perfume\nto this directory. It should contain the following static information (JSON properties):\n\n- `name`, `description`, `additionalInformation`: Static information in English (default language).\n- `detectorClassSimpleName`: Simple name (= class name, not fully qualified) of the `Detector` that is associated with this Perfume and that is responsible to detect the Perfume's code structure in the AST. With the default Perfumator configuration, the detectors for all Perfumes reside in the `src/main/java/de/jsilbereisen/perfumator/engine/detector/perfume` directory. The detector class **must** have a zero-arguments constructor (instantiated via Reflection) and **should** override `equals` and `hashCode` (using the `@EqualsAndHashCode` annotation from Lombok is recommended).\n- `i18nBaseBundleName`: Base name of the _ResourceBundle_ for internationalizing the `name`, `description`, `sources` and `additionalInformation` properties of this Perfume. See the later section _Adding a resource bundle ..._ for more information on how to add the resource bundle.\n- `sources`: List of sources that inspired this Perfume or where one can find additional information about it.\n- `relatedPattern`: Enum constant of `de.jsilbereisen.perfumator.model.perfume.RelatedPattern`. This way, one can signal for example whether this Perfume solves a smell / bug pattern or depicts a Design pattern.\n\n### ... with custom configurations\n\nAs the `PerfumeDetectionEngine.Builder` allows one to configure the `Registry\u003cPerfume\u003e` which is responsible for loading the Perfume definitions (plus invoke their internationalization if needed) and their detectors to use by the engine,\none can either create a `PerfumeRegistry` and supply custom values to the offered configuration constructor, or one can create a completely new implementation of the interface and supply that one.\n\nThis allows to store and load Perfume definitions and their detectors in custom locations. Also, the location where the internationalization resources can be found can be configured, or internationalization could be entirely dropped via a custom implementation, if not needed.\n\nThe addition of new Perfumes should then be similar to the previous section, just with the custom locations of the Perfumes, detectors and resources.\n\n\n## Adding a resource bundle ...\n\n### ... for a Code Perfume\n\nTo add a new resource bundle for a Code Perfume, you need to take the following\nsteps:\n\n1. Create a base resource in the `src/main/resources/i18n/perfumes` folder.\n2. Check that the name of the base resource **EXACTLY** matches (without the `.properties` file extension of course) the `i18nBaseBundleName` property in the associated Perfume definition JSON.\n3. The base resource bundle can be left empty, if the associated Perfume JSON definition already contains the English field values (English is the default application language).\n4. Now you can add support for other languages for your Perfume by adding other resources in the same folder and the same base name, extended with an _underscore_ ( \"_\" ) and the _language tag_, for example for the base resource/perfume \"foo\" and the language Spanish, you would add `foo_es.properties`.\n5. Make sure that if you add a resource for a language, that the language is generally supported by the application, meaning the tag is defined in the `de.jsilbereisen.perfumator.io.LanguageTag` class. If not, feel free to simply add a new constant to the class for your desired language.\n\nPlease check out existing resources for other Perfumes for guidance on which properties you can internationalize.\nPay attention specifically to the `sources` property, as it is a _list_ of strings in the Perfume JSON definition.\nThis is handled in the resource bundles by adding multiple `source#X` mappings, where _X_ is an ongoing number (starting from 1), so that one can\nspecify the internationalized list content in the correct order.\n\n### ... for the application itself\n\nSimply add the resource for the desired language to the `resources/i18n/application` directory, either for the\n_application_ base bundle (e.g. for Log messages or exception / error messages) or for the _commandline_ base bundle\n(command line interface).\n\n## Acknowledgements\n\nThis endeavor would not have been possible without the chair of Software Engineering II, especially my supervisor Prof.\nDr. Gordon Fraser and my advisor Philipp Straubinger, who continuously supported the work throughout the entire process,\nfrom the topic selection until the final submission. Thank you for your patience and the invaluable feedback.\n\n## License\n\nThis project is licensed under the Apache License v2.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fse2p%2Fperfumator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fse2p%2Fperfumator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fse2p%2Fperfumator/lists"}