{"id":16859574,"url":"https://github.com/raphw/declarative-parser","last_synced_at":"2025-04-11T07:51:39.828Z","repository":{"id":11963088,"uuid":"14535251","full_name":"raphw/declarative-parser","owner":"raphw","description":"A parser that is configured by annotating fields of a Java bean where all parsed content is reflected as instances of this bean.","archived":false,"fork":false,"pushed_at":"2013-11-23T13:46:37.000Z","size":192,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-03T18:12:06.762Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raphw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-11-19T19:21:58.000Z","updated_at":"2019-07-28T18:18:22.000Z","dependencies_parsed_at":"2022-08-24T03:10:16.864Z","dependency_job_id":null,"html_url":"https://github.com/raphw/declarative-parser","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphw%2Fdeclarative-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphw%2Fdeclarative-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphw%2Fdeclarative-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphw%2Fdeclarative-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raphw","download_url":"https://codeload.github.com/raphw/declarative-parser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239580702,"owners_count":19662806,"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":[],"created_at":"2024-10-13T14:18:26.226Z","updated_at":"2025-02-19T01:31:26.537Z","avatar_url":"https://github.com/raphw.png","language":"Java","readme":"A declarative parser based on Java beans\n---------------------\nThis miniature tool provides help with parsing a custom content format by creating Java beans that extract this data\nwhere each bean resembles a single row of content of a specified source. The mapping of the input to a Java bean is based\non regular expressions what allows great flexibility. However, the syntax of regular expressions is enhanced by\nproperties expressions that allow the direct mapping of bean properties within this regular expression describing these\ncontents.\n\nThis tool is intended to be as light-weight as possible and comes without dependencies. It is however quite extensible as\ndemonstrated below.\n\n#### Simple example\nThe tool is used by a single entry point, an instance of `BeanTransformer` which can read content for a specified bean. By\ndoing so, the parser only needs to build patterns for a specified bean a single time. Therefore, this tool performs equally\ngood as writing native content parsers, once it is set up.\n\nAs an example for the use of this tool, imagine you want to read in data from some sample file *sample.txt* containing\nthe following data in an imaginary format:\n\n```\n##This is a first value##foo\u0026\u00262319949,\n##This is a second value##bar\u0026\u0026741981,\n##This is a third value##\u0026\u0026998483,\n```\n\nThis tool would now allow you to directly translate this file by declaring the following Java bean:\n\n```\n@MatchBy(\"##@intro@##@value@\u0026\u0026@number@,\")\nclass MyBean {\n\n    private String intro;\n\n    @OptionalMatch\n    private String value;\n\n    private int number;\n\n    // Getters and setters...\n}\n```\n\nThe `@name@` expressions each represent a property in the bean which will be filled by the data found at this particular point\nwithin the regular expression. The expression can be escaped by preceeding the **first** `@` symbol with backslashes as for\nexample `\\\\@name@`. A back slash can be escaped in the same manner.\n\nWith calling `BeanTransformer.make(MyBean.class).read(new FileReader(\"./sample.txt\"))` you would receive a list of `MyBean`\ninstances where each instance resembles one line of the file. All properties would be matched to the according property name\nthat is declared in the bean.\n\n#### Matching properties\nThe `@MatchBy` annotation can also be used for fields within a bean that is used for matching. This tool will normally discover\na pattern by interpreting the type of a field that is referenced in the expression used for parsing the content. Since the\n`@number@` expression in the example above references a field of type `int`, the field would be matched against the regular expression\n`[0-9]+`, representing any non-decimal number. All other primitive types and their wrapper types are also equipped with a\npredefined matching pattern. All other types will by default be matched by a **non-greedy** match-everything pattern. After\nextracting a property, the type of the property will be tried to be instantiated by:\n\n1. Invoking a static function with the signature `valueOf(String)` defined on the type.\n2. Using a constructor taking a single `String` as its argument.\n\nThis default behavior can however be changed. A field can be annotated with `@ResolveMatchWith` which requires a subtype of\na `PropertyDelegate` as its single argument. An instance of this class will be instantiated for transforming expressions from\na string to a value and revers. The subclass needs to override the only constructor of `PropertyDelegate` and accept the same\ntypes as this constructor.\n\nAn optional match can be declared by annotating a field with `@OptionalMatch`. If no match can be made for such a field, the\n`PropertyDelegate`'s setter will never be invoked (when using a custom `PropertyDelegate`).\n\n#### Dealing with regular expressions\nAlways keep in mind that `@MatchBy` annotation take regular expressions as their arguments. Therefore, it is important to escape\nall special characters that are found in regular expressions such as for example `.\\\\*,[](){}+?^$`. Also, note that the\ndefault matching patterns for non-primitive types or their wrappers is **non-greedy**. This means that the pattern `@name@`\nwould match the line **foo** by only the first letter **f**. If you want to match the full line, you have to declare the matching\nexpression as `^@name@$` what is the regular expression for a full line match. Be aware that using regular expressions might\nrequire you to define a `@WritePattern` which is described below.\n\nUsing regular expressions allows you to specify matching constraints natively. Annotating a field with `@MatchBy(\"[a-z]{1,5]\")`\nwould for example allow for only matching lines where the property is represented by one to five lower case characters.\nConfiguring mismatch handling is described below.\n\n#### Writing beans\nSimilar to reading contents from a source, this utility allows to write a list of beans to a target. Without further\nconfiguration, the same pattern as in `@MatchBy` will be used for writing where the property expressions are substituted by\nthe bean values. This can however result in distorted output since symbols of regular expressions are written *as they are*.\nTherefore, a user can define an output pattern by declaring `@WritePattern`. This pattern understands the same type of property\nexpressions such as `@name` but does not use regular expressions. Remember that regular expressions must therefore not be escaped\nwhen a `@WritePattern` is specified. A property expression can however be escaped in the same manner as in a `@MatchBy` statement.\n\n#### Handling mismatches\nWhen a content source is parsed but a single line cannot be matched to the specified expression, the extraction will abort\nwith throwing a `TransformationException`. Empty lines will however be skipped. This behavior can be configured by declaring\na policy within `@Skip`. That way, a non-matched line can either ignored, throw an exception or be ignored for empty lines. An\nempty line a the end of a file is always ignored.\n\n#### Builder\nThe `BeanTransformer` offers a builder which allows to specify different properties. Mostly, it allows to override properties\nthat were declared in a specific bean such as the content pattern provided by `@MatchBy`, a `@Skip` policy or the `@WritePattern`.\nThis allows the reuse of a bean for different content sources that contain the same properties but differ in their display. Also,\nthis allows to provide a pattern at run time.\n\n#### Performance considerations\nAll beans are constructed and accessed via field reflection. (It is therefore not required to define setters and getters for beans.\nA default constructor is however required. In the process, primitive types are accessed as such and not wrapped in order to\navoid such overhead. Java reflection is usually considered to be slower than conventional access. However, modern JVMs such as\nthe HotSpot JVM are efficient in detecting the repetitive use of reflection  and compile such access into native byte code.\nTherefore, this tool should not perform worse than a hand-written matcher once the `BeanTransformer` is set up.\n\n#### Extension points\nBesides providing your own `PropertyDelegate`s, it is possible to implement a custom `IDelegationFactory` which is responsible\nfor creating (custom) `PropertyDelegate`s for any field. The default implementation `SimpleDelegationFactory` provides an example \nfor such an implementation. That way, it would be for example possible to automatically create suitable patterns for [bean \nvalidation (JSR-303) annotations](http://beanvalidation.org/1.0/spec/).\n\nLicensed under the Apache Software License, Version 2.0\n\n[![Build Status](https://travis-ci.org/raphw/declarative-parser.png)](https://travis-ci.org/raphw/declarative-parser)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphw%2Fdeclarative-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraphw%2Fdeclarative-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphw%2Fdeclarative-parser/lists"}