diff --git a/.github/renovate.json b/.github/renovate.json
new file mode 100644
index 00000000..28965bad
--- /dev/null
+++ b/.github/renovate.json
@@ -0,0 +1,6 @@
+{
+ "extends": [
+ "config:base",
+ ":gitSignOff"
+ ]
+}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..50ea7865
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,43 @@
+name: build
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ java-version: [8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+ - name: Set up Java ${{matrix.java-version}}
+ uses: actions/setup-java@v5
+ with:
+ distribution: zulu
+ java-version: ${{matrix.java-version}}
+ - name: Run tests
+ run: ./mvnw --batch-mode --no-transfer-progress -e test
+
+ coverage:
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+ - name: Create code coverage report
+ run: ./mvnw --batch-mode --no-transfer-progress -e test jacoco:report
+ - name: Upload code coverage report
+ uses: codecov/codecov-action@v5
+ with:
+ files: target/site/jacoco/jacoco.xml
+ name: codecov
+
+ dependency-check:
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+ - name: Check dependencies
+ run: ./mvnw --batch-mode --no-transfer-progress -e dependency-check:check -DnvdApiKey='${{ secrets.NVD_API_KEY }}' -DossIndexUsername='${{ secrets.OSSINDEX_USERNAME }}' -DossIndexPassword='${{ secrets.OSSINDEX_TOKEN }}'
diff --git a/.gitignore b/.gitignore
index 62404111..37a81e09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
*.iml
.idea
target
+.mvn/wrapper/*.jar
+.mvn/settings.xml
\ No newline at end of file
diff --git a/.mvn/owasp-suppressions.xml b/.mvn/owasp-suppressions.xml
new file mode 100644
index 00000000..ddeb92a3
--- /dev/null
+++ b/.mvn/owasp-suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ ^pkg:maven/com\.google\.guava/guava@.*$
+ CVE-2020-8908
+
+
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..6a6b8b2c
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 0206b6fd..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-language: java
-install: "mvn install -DskipTests=true"
-script: "mvn test -e"
-jdk:
- - oraclejdk7
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..5a1e67ca
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,65 @@
+# Contributing
+
+Contributions are very welcome!
+
+## How to contribute
+
+We love pull requests. Here is a quick guide:
+
+1. Fork the repo.
+2. Create a new branch from `master`.
+3. Add your change together with necessary tests.
+4. Run `mvn clean verify` and ensure all tests are passing.
+5. Commit with a DCO sign-off message (see next section) and push to your fork/branch.
+6. Create a pull request.
+
+## Sign your work – the Developer's Certificate of Origin
+The sign-off is a simple line at the end of the explanation for the patch,
+which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch.
+The rules are pretty simple:
+You need to certify the below (from [developercertificate.org](https://developercertificate.org/)):
+
+> Developer's Certificate of Origin 1.1
+>
+> By making a contribution to this project, I certify that:
+>
+> (a) The contribution was created in whole or in part by me and I
+> have the right to submit it under the open source license
+> indicated in the file; or
+>
+> (b) The contribution is based upon previous work that, to the best
+> of my knowledge, is covered under an appropriate open source
+> license and I have the right under that license to submit that
+> work with modifications, whether created in whole or in part
+> by me, under the same open source license (unless I am
+> permitted to submit under a different license), as indicated
+> in the file; or
+>
+> (c) The contribution was provided directly to me by some other
+> person who certified (a), (b) or (c) and I have not modified
+> it.
+>
+> (d) I understand and agree that this project and the contribution
+> are public and that a record of the contribution (including all
+> personal information I submit with it, including my sign-off) is
+> maintained indefinitely and may be redistributed consistent with
+> this project or the open source license(s) involved.
+
+#### DCO Sign-Off Methods
+
+The DCO requires a sign-off message in the following format appear on each commit in the pull request:
+
+ Signed-off-by: Random J Developer
+
+using your real name (sorry, no pseudonyms or anonymous contributions.)
+
+The DCO text can either be manually added to your commit body,
+or you can add either **`-s`** or **`--signoff`** to your usual **`git commit`** commands.
+If you forget to add the sign-off you can also amend a previous commit with the sign-off
+by running **`git commit --amend -s`**.
+If you've pushed your changes to Github already
+you'll need to force push your branch after this with **`git push -f`**.
+
+#### Alternative Sign-Off Methods in rare cases
+
+If it is really no option for you to disclose your real name and email address, there might be a chance that you can get your contribution accepted. In this case please contact the maintainers directly and verify the adherence to the DCO of the contribution manually. This might include quite some legal overhead for both parties.
diff --git a/LICENSE-2.0.txt b/LICENSE
similarity index 100%
rename from LICENSE-2.0.txt
rename to LICENSE
diff --git a/LICENSE-2.0.html b/LICENSE-2.0.html
deleted file mode 100644
index 4ff2e0a5..00000000
--- a/LICENSE-2.0.html
+++ /dev/null
@@ -1,427 +0,0 @@
-
-
-
- Apache License, Version 2.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
"License" shall mean the terms and conditions for use, reproduction, and
-distribution as defined by Sections 1 through 9 of this document.
-
"Licensor" shall mean the copyright owner or entity authorized by the
-copyright owner that is granting the License.
-
"Legal Entity" shall mean the union of the acting entity and all other
-entities that control, are controlled by, or are under common control with
-that entity. For the purposes of this definition, "control" means (i) the
-power, direct or indirect, to cause the direction or management of such
-entity, whether by contract or otherwise, or (ii) ownership of fifty
-percent (50%) or more of the outstanding shares, or (iii) beneficial
-ownership of such entity.
-
"You" (or "Your") shall mean an individual or Legal Entity exercising
-permissions granted by this License.
-
"Source" form shall mean the preferred form for making modifications,
-including but not limited to software source code, documentation source,
-and configuration files.
-
"Object" form shall mean any form resulting from mechanical transformation
-or translation of a Source form, including but not limited to compiled
-object code, generated documentation, and conversions to other media types.
-
"Work" shall mean the work of authorship, whether in Source or Object form,
-made available under the License, as indicated by a copyright notice that
-is included in or attached to the work (an example is provided in the
-Appendix below).
-
"Derivative Works" shall mean any work, whether in Source or Object form,
-that is based on (or derived from) the Work and for which the editorial
-revisions, annotations, elaborations, or other modifications represent, as
-a whole, an original work of authorship. For the purposes of this License,
-Derivative Works shall not include works that remain separable from, or
-merely link (or bind by name) to the interfaces of, the Work and Derivative
-Works thereof.
-
"Contribution" shall mean any work of authorship, including the original
-version of the Work and any modifications or additions to that Work or
-Derivative Works thereof, that is intentionally submitted to Licensor for
-inclusion in the Work by the copyright owner or by an individual or Legal
-Entity authorized to submit on behalf of the copyright owner. For the
-purposes of this definition, "submitted" means any form of electronic,
-verbal, or written communication sent to the Licensor or its
-representatives, including but not limited to communication on electronic
-mailing lists, source code control systems, and issue tracking systems that
-are managed by, or on behalf of, the Licensor for the purpose of discussing
-and improving the Work, but excluding communication that is conspicuously
-marked or otherwise designated in writing by the copyright owner as "Not a
-Contribution."
-
"Contributor" shall mean Licensor and any individual or Legal Entity on
-behalf of whom a Contribution has been received by Licensor and
-subsequently incorporated within the Work.
-
2. Grant of Copyright License. Subject to the
-terms and conditions of this License, each Contributor hereby grants to You
-a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-copyright license to reproduce, prepare Derivative Works of, publicly
-display, publicly perform, sublicense, and distribute the Work and such
-Derivative Works in Source or Object form.
-
3. Grant of Patent License. Subject to the terms
-and conditions of this License, each Contributor hereby grants to You a
-perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-(except as stated in this section) patent license to make, have made, use,
-offer to sell, sell, import, and otherwise transfer the Work, where such
-license applies only to those patent claims licensable by such Contributor
-that are necessarily infringed by their Contribution(s) alone or by
-combination of their Contribution(s) with the Work to which such
-Contribution(s) was submitted. If You institute patent litigation against
-any entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that the Work or a Contribution incorporated within the Work constitutes
-direct or contributory patent infringement, then any patent licenses
-granted to You under this License for that Work shall terminate as of the
-date such litigation is filed.
-
4. Redistribution. You may reproduce and
-distribute copies of the Work or Derivative Works thereof in any medium,
-with or without modifications, and in Source or Object form, provided that
-You meet the following conditions:
-
-
You must give any other recipients of the Work or Derivative Works a
-copy of this License; and
-
-
You must cause any modified files to carry prominent notices stating
-that You changed the files; and
-
-
You must retain, in the Source form of any Derivative Works that You
-distribute, all copyright, patent, trademark, and attribution notices from
-the Source form of the Work, excluding those notices that do not pertain to
-any part of the Derivative Works; and
-
-
If the Work includes a "NOTICE" text file as part of its distribution,
-then any Derivative Works that You distribute must include a readable copy
-of the attribution notices contained within such NOTICE file, excluding
-those notices that do not pertain to any part of the Derivative Works, in
-at least one of the following places: within a NOTICE text file distributed
-as part of the Derivative Works; within the Source form or documentation,
-if provided along with the Derivative Works; or, within a display generated
-by the Derivative Works, if and wherever such third-party notices normally
-appear. The contents of the NOTICE file are for informational purposes only
-and do not modify the License. You may add Your own attribution notices
-within Derivative Works that You distribute, alongside or as an addendum to
-the NOTICE text from the Work, provided that such additional attribution
-notices cannot be construed as modifying the License.
-
-
-You may add Your own copyright statement to Your modifications and may
-provide additional or different license terms and conditions for use,
-reproduction, or distribution of Your modifications, or for any such
-Derivative Works as a whole, provided Your use, reproduction, and
-distribution of the Work otherwise complies with the conditions stated in
-this License.
-
-
-
-
-
5. Submission of Contributions. Unless You
-explicitly state otherwise, any Contribution intentionally submitted for
-inclusion in the Work by You to the Licensor shall be under the terms and
-conditions of this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify the
-terms of any separate license agreement you may have executed with Licensor
-regarding such Contributions.
-
6. Trademarks. This License does not grant
-permission to use the trade names, trademarks, service marks, or product
-names of the Licensor, except as required for reasonable and customary use
-in describing the origin of the Work and reproducing the content of the
-NOTICE file.
-
7. Disclaimer of Warranty. Unless required by
-applicable law or agreed to in writing, Licensor provides the Work (and
-each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
-without limitation, any warranties or conditions of TITLE,
-NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You
-are solely responsible for determining the appropriateness of using or
-redistributing the Work and assume any risks associated with Your exercise
-of permissions under this License.
-
8. Limitation of Liability. In no event and
-under no legal theory, whether in tort (including negligence), contract, or
-otherwise, unless required by applicable law (such as deliberate and
-grossly negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special,
-incidental, or consequential damages of any character arising as a result
-of this License or out of the use or inability to use the Work (including
-but not limited to damages for loss of goodwill, work stoppage, computer
-failure or malfunction, or any and all other commercial damages or losses),
-even if such Contributor has been advised of the possibility of such
-damages.
-
9. Accepting Warranty or Additional Liability.
-While redistributing the Work or Derivative Works thereof, You may choose
-to offer, and charge a fee for, acceptance of support, warranty, indemnity,
-or other liability obligations and/or rights consistent with this License.
-However, in accepting such obligations, You may act only on Your own behalf
-and on Your sole responsibility, not on behalf of any other Contributor,
-and only if You agree to indemnify, defend, and hold each Contributor
-harmless for any liability incurred by, or claims asserted against, such
-Contributor by reason of your accepting any such warranty or additional
-liability.
-
END OF TERMS AND CONDITIONS
-
APPENDIX: How to apply the Apache License to your work
-
To apply the Apache License to your work, attach the following boilerplate
-notice, with the fields enclosed by brackets "[]" replaced with your own
-identifying information. (Don't include the brackets!) The text should be
-enclosed in the appropriate comment syntax for the file format. We also
-recommend that a file or class name and description of purpose be included
-on the same "printed page" as the copyright notice for easier
-identification within third-party archives.
-
-
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 00000000..5910ca24
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,16 @@
+
+config-builder
+--------------
+
+Copyright 2013-2018 Matthias Bollwein (matthias.bollwein@tngtech.com)
+Copyright 2013-2018 Andreas Würl (andreas.wuerl@tngtech.com)
+Copyright 2013-2018 Thomas Endres (thomas.endres@tngtech.com)
+Copyright 2013-2014 Andreas Schmid (andreas.schmid@tngtech.com)
+Copyright 2013-2014 Jan Schäfer (jan.schaefer@tngtech.com)
+Copyright 2013-2015 Fabian Winter (fabian.winter@tngtech.com)
+Copyright 2014 Andre Wallat
+Copyright 2017-2020 Manfred Hanke (manfred.hanke@tngtech.com)
+Copyright 2018 Johannes Najjar (johannes.najjar@tngtech.com)
+Copyright 2020 Daniel Kraschewski (daniel.kraschewski@tngtech.com)
+
+This product includes software developed at TNG Technology Consulting GmbH (https://www.tngtech.com/).
\ No newline at end of file
diff --git a/README.md b/README.md
index 6b1a9be4..51bf392b 100644
--- a/README.md
+++ b/README.md
@@ -1,84 +1,86 @@
-Java Config-Builder [](https://travis-ci.org/TNG/config-builder)
-==================
+Java Config-Builder
+ [](https://github.com/TNG/config-builder/actions/workflows/build.yml?query=branch%3Amaster)
+ [](https://app.codecov.io/gh/TNG/config-builder)
+ [](http://opensource.org/licenses/Apache-2.0)
+ [](https://maven-badges.herokuapp.com/maven-central/com.tngtech.java/config-builder)
+ [](https://javadoc.io/doc/com.tngtech.java/config-builder)
+===================
#### Table of Contents
-[What It Is](#what-is-it)
-[Motivation](#motivation)
+[What It Is](#what-it-is)
+[Motivation](#motivation)
[How To Build Your Config](#how-to-build-your-config)
-[How To Merge With An Existing Config](#how-to-merge-with-an-existing-config)
+[How To Import An Existing Config](#how-to-import-an-existing-config)
[Usage example](#usage-example)
+[Presentation](#presentation)
[Java Doc](#java-doc)
What It Is
----------
+The Config-Builder makes use of annotations and reflections in order to build configured instances of custom classes.
-The ConfigBuilder makes use of annotations and reflections in order to build configured instances of custom classes.
-
-Its features include
+Its features include
1. defining default values and loading of values from properties files, system properties, the command line and others
2. configuring of not only String values, but fields of arbitrary types
-3. configuring of collection fields
-4. merging configs
-5. JSR303 validation of the instances it builds.
+3. configuring of collection fields
+4. merging configs
+5. [JSR380](https://www.jcp.org/en/jsr/detail?id=380) validation of the instances it builds.
Motivation
----------
-
-Many Java Projects include one or more classes that store configuration values and objects. Often, these come from
+Many Java projects include one or more classes that store configuration values and objects. These often come from
properties files, system properties and environment variables or command line arguments, which requires the developer
to implement the finding and loading of files, parsing the values etc. for every new project.
-This is is a time-consuming process, so why not spare this time and get started much faster? Although there are libraries
-that implement the loading of properties files and some possibilities of building configured objects e.g. in Spring,
+This is a time-consuming process, so why not spare this time and get started much faster? Although there are libraries
+that implement the loading of properties files and some possibilities of building configured objects e.g. in Spring,
there hasn't been a really easy-yet-powerful solution so far.
-This is where the Config Builder comes in. It doesn't require any additional classes besides the config itself.
-Instead of manually implementing the loading of values from files etc., building a config can now be easily done
+This is where the Config-Builder comes in. It doesn't require any additional classes besides the config itself.
+Instead of manually implementing the loading of values from files etc., building a config can now be easily done
by using annotations.
How To Build Your Config
------------------------
-
-####1. Create your class:
+#### 1. Create your class:
```java
public class Config {
private String someNumber;
private Collection stringCollection;
- ...
+ // ...
}
```
-####2. Annotate the class (configure the loading of properties files)
-If you want the ConfigBuilder to get values from properties files,
-you can specify the files' basenames (no file extension or path) by
-annotating your config class with the @PropertiesFiles annotation.
-You can specify multiple basenames like this:
+#### 2. Annotate the class (configure the loading of properties files)
+If you want the Config-Builder to get values from properties files,
+you can specify the files' basenames (no file extension or path) by
+annotating your config class with the `@PropertiesFiles` annotation.
+You can specify multiple basenames like this:
```java
@PropertiesFiles({file1,file2,...})
```
-By default, properties files are loaded using the PropertyLoader's default config, which
+By default, properties files are loaded using the `PropertyLoader`'s default config, which
searches for files in the current directory, the ContextClassLoader and the user's home directory.
-You can manually specify the search locations by annotating your config class with the @PropertyLocations annotation, e.g.
+You can manually specify the search locations by annotating your config class with the `@PropertyLocations` annotation, e.g.
```java
@PropertyLocations(directories = {"/home/user"}, resourcesForClasses={MyApp.class}, contextClassLoader = true)
```
-The PropertyLoader also searches for files with the default suffixes, i.e. the user name, local host names and 'override'.
-You can manually set the suffixes by annotating your config class with the @PropertySuffixes annotation like this:
+The `PropertyLoader` also searches for files with the default suffixes, i.e. the user name, local host names and 'override'.
+You can manually set the suffixes by annotating your config class with the `@PropertySuffixes` annotation like this:
```java
@PropertySuffixes(extraSuffixes = {"tngtech","myname"}, hostNames = true)
```
-The default file extensions are .properties and .xml. You can replace the .properties file extension with your own
-by annotating your config class with
+The default file extensions are `.properties` and `.xml`. You can replace the .properties file extension with your own
+by annotating your config class with
```java
@PropertyExtension("fileextension")
```
-####3. Annotate the fields
-
-#####3.1 Get the String value
+#### 3. Annotate the fields
+##### 3.1 Get the String value
There are five annotations that specify where the String value that configures a field comes from:
```java
@DefaultValue("value")
@@ -89,61 +91,63 @@ There are five annotations that specify where the String value that configures a
```
By default, when parsing the annotations, priority is as above, i.e. any value found on the command line overwrites a value found in properties, which in turn overwrites the environment variable value and so on.
-This order can be customized, see [4.](#4-change-the-order-in-which-annotations-are-processed-and-use-your-own-error-messages).
+This order can be customized, see [§5 (Change the order in which annotations are processed)](#5-change-the-order-in-which-annotations-are-processed).
-#####3.2 Transform it to any object or a collection
+##### 3.2 Transform it to any object or a collection
Fields don't have to be Strings. You can configure collection fields or even any type you wish (or a collection of that type).
Some simple transformers are included and used by default, e.g. a String will automatically be converted to an integer, a
-boolean value or even a collection as needed.
+boolean value, an enum value, or even a collection as needed.
+
+If you need more complex transformers, you can also implement your own by extending the `TypeTransformer` class, and specifying them in the `@TypeTransformers` annotation.
-If you need more complex transformers, you can also implement your own by extending the TypeTransformer class, and specifying them in the ```@TypeTransformers``` annotation.
-
-Finally, the original value may not always be a String. To support this case, the annotation takes a list of possible transformers, and the one with the right
-source and target types is automatically detected and used.
-
-####4. Add JSR validation annotations and/or define a custom validation method
+Finally, the original value may not always be a String. To support this case, the annotation takes a list of possible transformers, and the one with the right
+source and target types is automatically detected and used.
+##### 3.3 Prevent sensitive data from being logged
+Resolved values are usually logged at debug level.
+If this is not desired, just add the `@DoNotLogValue` annotation to the field containing your sensitive data.
+
+#### 4. Add JSR validation annotations and/or define a custom validation method
After an instance of your config is built, it is automatically validated. You can either use JSR validation annotations
-(@NotNull,...) or define a custom validation method:
+(`@NotNull`, ...) or define a custom validation method:
```java
@Validation
private void validate() {
- <...>
+ // ...
}
```
-####5. Change the order in which annotations are processed and use your own error messages
-
+#### 5. Change the order in which annotations are processed
You can change the order in which annotations are processed globally or individually for each field.
-To specify a global order for parsing ValueExtractorAnnotation annotations, annotate the class with the
-@LoadingOrder annotation. To change the order for a certain field, annotate the field.
-The order may only contain ValueExtractorAnnotations, i.e.
-CommandLineValue.class, PropertyValue.class and DefaultValue.class. Example:
+To specify a global order for parsing `ValueExtractorAnnotation` annotations, annotate the class with the
+`@LoadingOrder` annotation. To change the order for a certain field, annotate the field.
+The `@LoadingOrder` may only contain the following values:
```java
-@LoadingOrder({PropertyValue.class, EnvironmentVariableValue.class, SystemPropertyValue.class, CommandLineValue.class, DefaultValue.class})
+@LoadingOrder({PropertyValue.class, EnvironmentVariableValue.class, SystemPropertyValue.class, CommandLineValue.class, ImportedValue.class, DefaultValue.class})
```
-To specify your own error messages file (which is loaded by the PropertyLoader with the same settings as other the properties files),
-annotate the class with the @ErrorMessageFile annotation:
+#### 6. Use your own error messages
+To specify your own error messages file (which is loaded by the `PropertyLoader` with the same settings as other the properties files),
+annotate the class with the `@ErrorMessageFile` annotation:
```java
@ErrorMessageFile("myErrorMessages")
```
-####6. Build an instance of your class
+#### 7. Build an instance of your class
```java
-Config myConfig = new ConfigBuilder(Config.class).withCommandLineArgs(args).build();
+Config myConfig = ConfigBuilder.on(Config.class).withCommandLineArgs(args).build();
```
-How To Merge With An Existing Config
-------------------------------------
-If you already have an instance of your config class and want to only configure the fields which are not null, use
+How To Import An Existing Config
+--------------------------------
+If you already have an instance of your config class and want to only configure the fields which are not `null`, use
```java
-newConfig = new ConfigBuilder(Config.class).withCommandLineArgs(args).merge(existingConfig);
+Config newConfig = ConfigBuilder.on(Config.class).withCommandLineArgs(args).withImportedConfiguration(existingConfig).build();
```
-Note that primitive type fields are always overwritten!
-Since primitive types can not be checked for 'null', it is not possible to check whether primitive fields of an existing config
+Note that primitive type fields are always overwritten!
+Since primitive types can not be checked for `null`, it is not possible to check whether primitive fields of an existing config
have already been set. Hence, for the moment, primitives are always overwritten.
Usage example
@@ -155,56 +159,58 @@ Say you have a config that looks like this:
@PropertySuffixes(extraSuffixes = {"tngtech","myname"}, hostNames = true)
public class Config {
- public static class StringToPidFixTransformer implements TypeTransformer {
+ public static class StringToPidFixTransformer extends TypeTransformer {
@Override
public PidFix transform(String input) {
- <...>
+ // ...
}
}
-
- @DefaultValue("false") // values are automatically be converted to primitive types
+
+ // default false, true if the option is present
@CommandLineValue(shortOpt="t", longOpt="test", hasArg=false) // this is a flag argument
private boolean runInTestMode;
-
- @DefaultValue("3")
+
+ @DefaultValue("3") // values are automatically be converted to primitive types
@CommandLineValue(shortOpt="rl", longOpt="runLevel", hasArg=true)
private int runLevel;
-
+
@EnvironmentVariableValue("PATH")
@PropertyValue("path") // maps to the key "path" in the properties file
private String path;
-
+
@SystemPropertyValue("user.name") // maps to the field "user.name" in the system properties
@NotEmpty("username.notEmpty") // JSR-303 validation (Field should not be empty)
private String userName;
-
- @TypeTransformer(StringToPidFixTransformer.class)
+
+ @TypeTransformers(StringToPidFixTransformer.class)
@CommandLineValue(shortOpt="pc", longOpt="pidFixCollection", hasArg=true)
private Collection pidFixCollection;
-
- @TypeTransformer(StringToPidFixTransformer.class)
+
+ @TypeTransformers(StringToPidFixTransformer.class)
@CommandLineValue(shortOpt="p", longOpt="pidFix", hasArg=true)
private PidFix pidFix;
-
+
@Validation
private void validate() {
- <...>
+ // ...
}
- ...
+
+ //...
}
```
To build a configured instance, simply call
```java
-Config myConfig = new ConfigBuilder(Config.class).withCommandLineArgs(args).build();
+Config myConfig = ConfigBuilder.on(Config.class).withCommandLineArgs(args).build();
```
Presentation
---------
-
+------------
A sample presentation can be found at http://tng.github.io/config-builder
-
Java Doc
--------
-
Full javadoc of the code can be found here http://tng.github.io/config-builder/javadoc
+
+How to contribute
+-----------------
+Please have a look at [CONTRIBUTING.md](CONTRIBUTING.md)
diff --git a/mvnw b/mvnw
new file mode 100755
index 00000000..08303327
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,250 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.0
+#
+# Optional ENV vars
+# -----------------
+# JAVA_HOME - location of a JDK home dir, required when download maven via java source
+# MVNW_REPOURL - repo url base for downloading maven distribution
+# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
+# ----------------------------------------------------------------------------
+
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
+
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+ [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+ native_path() { cygpath --path --windows "$1"; }
+ ;;
+esac
+
+# set JAVACMD and JAVACCMD
+set_java_home() {
+ # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+ if [ -n "${JAVA_HOME-}" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACCMD="$JAVA_HOME/jre/sh/javac"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ JAVACCMD="$JAVA_HOME/bin/javac"
+
+ if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+ echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+ echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+ return 1
+ fi
+ fi
+ else
+ JAVACMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v java
+ )" || :
+ JAVACCMD="$(
+ 'set' +e
+ 'unset' -f command 2>/dev/null
+ 'command' -v javac
+ )" || :
+
+ if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+ echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+ return 1
+ fi
+ fi
+}
+
+# hash string like Java String::hashCode
+hash_string() {
+ str="${1:-}" h=0
+ while [ -n "$str" ]; do
+ char="${str%"${str#?}"}"
+ h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+ str="${str#?}"
+ done
+ printf %x\\n $h
+}
+
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
+
+die() {
+ printf %s\\n "$1" >&2
+ exit 1
+}
+
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+ case "${key-}" in
+ distributionUrl) distributionUrl="${value-}" ;;
+ distributionSha256Sum) distributionSha256Sum="${value-}" ;;
+ esac
+done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+ MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+ case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+ *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+ :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+ :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+ :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+ *)
+ echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+ distributionPlatform=linux-amd64
+ ;;
+ esac
+ distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+ ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_HOME="$HOME/.m2/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
+
+exec_maven() {
+ unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+ exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
+
+if [ -d "$MAVEN_HOME" ]; then
+ verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ exec_maven "$@"
+fi
+
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
+
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+ clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+ trap clean HUP INT TERM EXIT
+else
+ die "cannot create temp dir"
+fi
+
+mkdir -p -- "${MAVEN_HOME%/*}"
+
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+ distributionUrl="${distributionUrl%.zip}.tar.gz"
+ distributionUrlName="${distributionUrl##*/}"
+fi
+
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
+
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
+
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+ verbose "Found wget ... using wget"
+ wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+ verbose "Found curl ... using curl"
+ curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+ verbose "Falling back to use Java to download"
+ javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+ targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+ cat >"$javaSource" <<-END
+ public class Downloader extends java.net.Authenticator
+ {
+ protected java.net.PasswordAuthentication getPasswordAuthentication()
+ {
+ return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+ }
+ public static void main( String[] args ) throws Exception
+ {
+ setDefault( new Downloader() );
+ java.nio.file.Files.copy( new java.net.URL( args[0] ).openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+ }
+ }
+ END
+ # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+ verbose " - Compiling Downloader.java ..."
+ "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+ verbose " - Running Downloader.java ..."
+ "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
+fi
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+ distributionSha256Result=false
+ if [ "$MVN_CMD" = mvnd.sh ]; then
+ echo "Checksum validation is not supported for maven-mvnd." >&2
+ echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ elif command -v sha256sum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ elif command -v shasum >/dev/null; then
+ if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+ distributionSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+ echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+ exit 1
+ fi
+ if [ $distributionSha256Result = false ]; then
+ echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+ echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+# unzip and move
+if command -v unzip >/dev/null; then
+ unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+ tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
+fi
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
+
+clean || :
+exec_maven "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 00000000..33cbf988
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,146 @@
+<# : batch portion
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.3.0
+@REM
+@REM Optional ENV vars
+@REM MVNW_REPOURL - repo url base for downloading maven distribution
+@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
+@REM ----------------------------------------------------------------------------
+
+@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
+@SET __MVNW_CMD__=
+@SET __MVNW_ERROR__=
+@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
+@SET PSModulePath=
+@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
+ IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
+)
+@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
+@SET __MVNW_PSMODULEP_SAVE=
+@SET __MVNW_ARG0_NAME__=
+@SET MVNW_USERNAME=
+@SET MVNW_PASSWORD=
+@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
+@echo Cannot start maven from wrapper >&2 && exit /b 1
+@GOTO :EOF
+: end batch / begin powershell #>
+
+$ErrorActionPreference = "Stop"
+if ($env:MVNW_VERBOSE -eq "true") {
+ $VerbosePreference = "Continue"
+}
+
+# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
+$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
+if (!$distributionUrl) {
+ Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
+}
+
+switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
+ "maven-mvnd-*" {
+ $USE_MVND = $true
+ $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
+ $MVN_CMD = "mvnd.cmd"
+ break
+ }
+ default {
+ $USE_MVND = $false
+ $MVN_CMD = $script -replace '^mvnw','mvn'
+ break
+ }
+}
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
+if ($env:MVNW_REPOURL) {
+ $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
+ $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
+}
+$distributionUrlName = $distributionUrl -replace '^.*/',''
+$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
+$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
+$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
+$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
+
+if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
+ Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+ Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
+ exit $?
+}
+
+if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
+ Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
+}
+
+# prepare tmp dir
+$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
+$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
+$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
+trap {
+ if ($TMP_DOWNLOAD_DIR.Exists) {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+ }
+}
+
+New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
+
+# Download and Install Apache Maven
+Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+Write-Verbose "Downloading from: $distributionUrl"
+Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+$webclient = New-Object System.Net.WebClient
+if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
+ $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
+}
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
+if ($distributionSha256Sum) {
+ if ($USE_MVND) {
+ Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
+ }
+ Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
+ if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
+ Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
+ }
+}
+
+# unzip and move
+Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
+Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
+try {
+ Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
+} catch {
+ if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
+ Write-Error "fail to move MAVEN_HOME"
+ }
+} finally {
+ try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
+ catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
+}
+
+Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
diff --git a/pom.xml b/pom.xml
index f8ee0683..9ba7fc27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,28 +4,36 @@
4.0.0com.tngtech.javaconfig-builder
- 1.1-SNAPSHOT
+ 1.8.2-SNAPSHOTjarConfig-BuilderThe Config Builder creates fully configured instances of config classes, using values from various sources like properties files, command line arguments etc.https://github.com/TNG/config-builder
+
The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
+ https://www.apache.org/licenses/LICENSE-2.0.txtrepo
+
git@github.com:TNG/config-builder.git
- scm:git:git@github.com:TNG/config-builder.git
- scm:git:git@github.com:TNG/config-builder.git
- HEAD
-
+ scm:git:https://github.com/TNG/config-builder.git
+ scm:git:https://github.com/TNG/config-builder.git
+ HEAD
+
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+
Matthias Bollwein
- matthias.bollwein@tngtech.comTNG Technology Consulting
@@ -35,36 +43,113 @@
Andreas Würl
- andreas.wuerl@tngtech.com
+ TNG Technology Consulting
+
+
+ Manfred Hanke
+ manfred.hanke@tngtech.com
+ TNG Technology Consulting
+
+
+ Jan Thiart
+ jan.thiart@tngtech.comTNG Technology ConsultingTNG Technology Consulting
- http://www.tngtech.com/
+ https://www.tngtech.com/
-
- org.sonatype.oss
- oss-parent
- 7
-
+
+
+ UTF-8
+ UTF-8
+ github
+ 1.8
+
+
+ 1.10.0
+ 33.5.0-jre
+ 6.2.5.Final
+ 3.0.4
+ 1.5.1
+ 0.10.2
+ 2.0.17
+
+ 3.27.6
+ 5.13.4
+ 4.11.0
+
+
+ 3.1.1
+ 1.7.0
+ 3.14.1
+ 0.8.13
+ 3.5.4
+ 12.1.6
+ 3.3.1
+ 3.12.0
+ 3.2.8
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ ${maven-release-plugin.version}
+
+ true
+ sonatype-release
+ deploy
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ ${nexus-staging-maven-plugin.version}
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+
+
+
org.apache.maven.pluginsmaven-compiler-plugin
- 2.3.2
+ ${maven-compiler-plugin.version}
- 1.7
- 1.7
+ ${java.version}
+ ${java.version}
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco-maven-plugin.version}
+
+
+ prepare-agent
+
+ prepare-agent
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+ org.apache.maven.pluginsmaven-source-plugin
- 2.2.1
+ ${maven-source-plugin.version}attach-sources
@@ -78,28 +163,44 @@
org.apache.maven.pluginsmaven-javadoc-plugin
- 2.9.1
+ ${maven-javadoc-plugin.version}attach-javadocsjar
+
+ ${java.version}
+
+
+
+
+ org.owasp
+ dependency-check-maven
+ ${dependency-check-maven.version}
+
+ 5
+ .mvn/owasp-suppressions.xml
+
+
- signing
+
+ sonatype-releaseorg.apache.maven.pluginsmaven-gpg-plugin
- 1.4
+ ${maven-gpg-plugin.version}sign-artifacts
@@ -116,72 +217,68 @@
-
+
- com.tngtech.java
- property-loader
- 1.1
+ commons-cli
+ commons-cli
+ ${commons-cli.version}
-
- junit
- junit
- 4.11
- test
+ com.google.guava
+ guava
+ ${guava.version}
- org.mockito
- mockito-all
- 1.9.5
- test
+ org.hibernate.validator
+ hibernate-validator
+ ${hibernate-validator.version}
- org.unitils
- unitils-core
- 3.3
- test
+ org.glassfish
+ jakarta.el
+ ${jakarta-el.version}
- com.google.guava
- guava
- 15.0
+ com.tngtech.java
+ property-loader
+ ${property-loader.version}org.reflectionsreflections
- 0.9.8
-
-
- cglib
- cglib
- 2.2.2
+ ${reflections.version}
- commons-cli
- commons-cli
- 1.2
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
- javax.validation
- validation-api
- 1.0.0.GA
+ org.assertj
+ assertj-core
+ ${assertj-core.version}
+ test
- log4j
- log4j
- 1.2.17
+ org.junit.jupiter
+ junit-jupiter
+ ${junit-jupiter.version}
+ test
- org.hibernate
- hibernate-validator-annotation-processor
- 4.1.0.Final
+ org.mockito
+ mockito-junit-jupiter
+ ${mockito-junit-jupiter.version}
+ testorg.slf4j
- slf4j-log4j12
- 1.5.2
+ slf4j-reload4j
+ ${slf4j.version}
+ test
-
diff --git a/src/main/java/com/tngtech/configbuilder/ConfigBuilder.java b/src/main/java/com/tngtech/configbuilder/ConfigBuilder.java
index 6f2cb89b..27d9597c 100644
--- a/src/main/java/com/tngtech/configbuilder/ConfigBuilder.java
+++ b/src/main/java/com/tngtech/configbuilder/ConfigBuilder.java
@@ -1,62 +1,69 @@
package com.tngtech.configbuilder;
import com.tngtech.configbuilder.annotation.configuration.LoadingOrder;
+import com.tngtech.configbuilder.annotation.configuration.PropertyNamePrefix;
import com.tngtech.configbuilder.annotation.propertyloaderconfiguration.ErrorMessageFile;
import com.tngtech.configbuilder.configuration.BuilderConfiguration;
import com.tngtech.configbuilder.configuration.ErrorMessageSetup;
-import com.tngtech.configbuilder.util.ConfigBuilderFactory;
import com.tngtech.configbuilder.util.*;
import com.tngtech.propertyloader.PropertyLoader;
+import com.tngtech.propertyloader.impl.DefaultPropertyFilterContainer;
+import com.tngtech.propertyloader.impl.DefaultPropertyLocationContainer;
+import com.tngtech.propertyloader.impl.DefaultPropertySuffixContainer;
+import com.tngtech.propertyloader.impl.interfaces.PropertyLoaderFilter;
import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Arrays;
import java.util.List;
+import java.util.Properties;
/**
* Builds a config object.
* ConfigBuilder instantiates a class and sets fields of the instance by parsing annotations and
* loading values from properties files or the command line. It validates the instance by parsing JSR303 constraint annotations.
- *
+ *
* Fields of the config class can have the following annotations:
* {@link com.tngtech.configbuilder.annotation.valueextractor.DefaultValue}
* {@link com.tngtech.configbuilder.annotation.valueextractor.PropertyValue}
* {@link com.tngtech.configbuilder.annotation.valueextractor.CommandLineValue}
* {@link com.tngtech.configbuilder.annotation.valueextractor.SystemPropertyValue}
* {@link com.tngtech.configbuilder.annotation.valueextractor.EnvironmentVariableValue}
- * {@link LoadingOrder}
- *
+ * {@link LoadingOrder}
+ *
* Properties files are loaded with a PropertyLoader using its default config. In order to change settings for the PropertyLoader, the config class may be annotated with
* {@link com.tngtech.configbuilder.annotation.propertyloaderconfiguration.PropertiesFiles}
* {@link com.tngtech.configbuilder.annotation.propertyloaderconfiguration.PropertyLocations}
* {@link com.tngtech.configbuilder.annotation.propertyloaderconfiguration.PropertySuffixes}
- * {@link com.tngtech.configbuilder.annotation.propertyloaderconfiguration.PropertyExtension}
- *
+ * {@link com.tngtech.configbuilder.annotation.propertyloaderconfiguration.PropertyExtension}
+ *
* To specify a global order for parsing {@link com.tngtech.configbuilder.annotation.valueextractor.ValueExtractorAnnotation} annotations, annotate the class with
- * {@link LoadingOrder}
- *
+ * {@link LoadingOrder}
+ *
* To specify your own error messages file (which is loaded by the PropertyLoader with the same settings as other the properties files), annotate the class with
- * {@link ErrorMessageFile}
+ * {@link ErrorMessageFile}
*
* @param The type of the config class which shall be instantiated.
* @author Matthias Bollwein
* @version 0.1-SNAPSHOT
*/
public class ConfigBuilder {
-
+ private final static Logger LOGGER = LoggerFactory.getLogger(CommandLineHelper.class);
+ public static final Object AT_CONTEXT_CLASS_PATH = new Object();
+
private final BuilderConfiguration builderConfiguration;
private final CommandLineHelper commandLineHelper;
private final FieldSetter fieldSetter;
private final ConfigValidator configValidator;
private final ErrorMessageSetup errorMessageSetup;
private final ConstructionHelper constructionHelper;
-
- private Class configClass;
- private Options commandLineOptions;
- private PropertyLoader propertyLoader;
+ private final Class configClass;
+ private final PropertyLoader propertyLoader;
+ private final Properties additionalProperties;
private String[] commandLineArgs = {};
-
+
protected ConfigBuilder(Class configClass, ConfigBuilderFactory configBuilderFactory) {
-
configBuilderFactory.initialize();
this.configClass = configClass;
this.builderConfiguration = configBuilderFactory.getInstance(BuilderConfiguration.class);
@@ -65,16 +72,15 @@ protected ConfigBuilder(Class configClass, ConfigBuilderFactory configBuilder
this.fieldSetter = configBuilderFactory.getInstance(FieldSetter.class);
this.errorMessageSetup = configBuilderFactory.getInstance(ErrorMessageSetup.class);
this.constructionHelper = configBuilderFactory.getInstance(ConstructionHelper.class);
-
- propertyLoader = configBuilderFactory.getInstance(PropertyLoaderConfigurator.class).configurePropertyLoader(configClass);
- commandLineOptions = commandLineHelper.getOptions(configClass);
+ this.additionalProperties = configBuilderFactory.createInstance(Properties.class);
+ this.propertyLoader = configBuilderFactory.getInstance(PropertyLoaderConfigurator.class).configurePropertyLoader(configClass);
}
/**
* @param configClass The config class of which an instance shall be built.
*/
public ConfigBuilder(Class configClass) {
- this(configClass,new ConfigBuilderFactory());
+ this(configClass, new ConfigBuilderFactory());
}
/**
@@ -91,8 +97,8 @@ public ConfigBuilder withCommandLineArgs(String[] args) {
/**
* Imports the values from the given object according to the field names in the annotations
- * @param importedConfiguration
- * @return
+ * @param importedConfiguration configuration object to be imported
+ * @return the instance of ConfigBuilder
*/
public ConfigBuilder withImportedConfiguration(Object importedConfiguration) {
builderConfiguration.setImportedConfiguration(importedConfiguration);
@@ -100,23 +106,140 @@ public ConfigBuilder withImportedConfiguration(Object importedConfiguration)
}
/**
- * Configures the Config Builder to load given properties files instead of those specified in the config class.
+ * Configures the Config Builder to load given property files instead of those specified in the config class.
*
- * @param baseNames
- * @return
+ * @param baseNames base names of the property files to be loaded
+ * @return the instance of ConfigBuilder
*/
public ConfigBuilder overridePropertiesFiles(List baseNames) {
propertyLoader.withBaseNames(baseNames);
return this;
}
+ /**
+ * Provide additional properties which will overwrite the properties retrieved by the property loader
+ *
+ * @param properties to be added to the properties already present (starting from the result of the property loader)
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder addProperties(Properties properties) {
+ additionalProperties.putAll(properties);
+ return this;
+ }
+
+ /**
+ * set the extension to search for property files
+ * @param propertyExtension property file name extension to use
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertyExtension(String propertyExtension) {
+ propertyLoader.withExtension(propertyExtension);
+ return this;
+ }
+
+ /**
+ * set property suffix to b
+ * @param propertySuffix property file name suffix
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertySuffix(String propertySuffix) {
+ return withPropertySuffixes(propertySuffix);
+ }
+
+ /**
+ * replace list of possible property suffixes by given elements
+ * @param suffixArray one or more property file name suffix
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertySuffixes(String ... suffixArray) {
+ final DefaultPropertySuffixContainer suffixes = propertyLoader.getSuffixes();
+ suffixes.clear();
+ suffixes.addSuffixList(Arrays.asList(suffixArray));
+ return this;
+ }
+
+ /**
+ * add more property file suffixes to the list of possible property suffixes
+ * @param suffixArray one or more property file name suffix
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder addPropertySuffixes(String... suffixArray) {
+ propertyLoader.getSuffixes().addSuffixList(Arrays.asList(suffixArray));
+ return this;
+ }
+
+ /**
+ * set file name of property file to read
+ * @param fileName property file name
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertiesFile(String fileName) {
+ return withPropertiesFiles(fileName);
+ }
+
+ /**
+ * set file names of property files to read
+ * @param fileNames one or more property file names
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertiesFiles(String ... fileNames) {
+ propertyLoader.withBaseNames(Arrays.asList(fileNames));
+ return this;
+ }
+
+ /**
+ * set property locations
+ * @param propertyLocations lists of property locations which can be
+ * Strings: use as Directory
+ * Classes: use as Class Resource Location
+ * @return the instance of ConfigBuilder
+ */
+ public ConfigBuilder withPropertyLocations(Object ... propertyLocations) {
+ final DefaultPropertyLocationContainer locations = propertyLoader.getLocations();
+ locations.clear();
+ for (Object propertyLocation : propertyLocations) {
+ if (propertyLocation instanceof String) {
+ locations.atDirectory((String)propertyLocation);
+ } else if (propertyLocation instanceof Class) {
+ locations.atRelativeToClass((Class>)propertyLocation);
+ } else if (propertyLocation == AT_CONTEXT_CLASS_PATH) {
+ locations.atContextClassPath();
+ } else {
+ LOGGER.warn("unhandled property location '{}'", propertyLocation);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * set property filters in use
+ * @param propertyFilters property filters which should be applied after loading properties
+ * @return the instance of ConfigBuilder
+ */
+ @SafeVarargs
+ public final ConfigBuilder withPropertyFilters(Class extends PropertyLoaderFilter>... propertyFilters) {
+ final DefaultPropertyFilterContainer filterContainer = propertyLoader.getFilters();
+ final List filters = filterContainer.getFilters();
+ filters.clear();
+
+ for (Class extends PropertyLoaderFilter> propertyFilter : propertyFilters) {
+ try {
+ filters.add(propertyFilter.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ LOGGER.error("could not create filter '{}'", propertyFilter.getSimpleName(), e);
+ }
+ }
+ return this;
+ }
+
/**
* Prints a help message for all command line options that are configured in the config class.
*/
public void printCommandLineHelp() {
+ initializeErrorMessageSetup(propertyLoader);
HelpFormatter formatter = new HelpFormatter();
formatter.setSyntaxPrefix("Command Line Options for class " + configClass.getSimpleName() + ":");
- formatter.printHelp(" ", commandLineOptions);
+ formatter.printHelp(" ", commandLineHelper.getOptions(configClass));
}
/**
@@ -141,7 +264,15 @@ private void setupBuilderConfiguration(PropertyLoader propertyLoader) {
if (configClass.isAnnotationPresent(LoadingOrder.class)) {
builderConfiguration.setAnnotationOrder(configClass.getAnnotation(LoadingOrder.class).value());
}
- builderConfiguration.setProperties(propertyLoader.load());
+
+ if (configClass.isAnnotationPresent(PropertyNamePrefix.class)) {
+ builderConfiguration.setPropertyNamePrefixes(configClass.getAnnotation(PropertyNamePrefix.class).value());
+ }
+
+ final Properties properties = propertyLoader.load();
+ properties.putAll(additionalProperties);
+ builderConfiguration.setProperties(properties);
+
builderConfiguration.setCommandLine(commandLineHelper.getCommandLine(configClass, commandLineArgs));
}
@@ -149,4 +280,15 @@ private void initializeErrorMessageSetup(PropertyLoader propertyLoader) {
String errorMessageFile = configClass.isAnnotationPresent(ErrorMessageFile.class) ? configClass.getAnnotation(ErrorMessageFile.class).value() : null;
errorMessageSetup.initialize(errorMessageFile, propertyLoader);
}
+
+ /**
+ * Gets an instance of the ConfigBuilder for a given config class
+ *
+ * @param clazz config class for which the config builder is instantiated.
+ * @param generic type of the config class
+ * @return ConfigBuilder instance for config class
+ */
+ public static ConfigBuilder on(Class clazz) {
+ return new ConfigBuilder<>(clazz);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/configuration/DoNotLogValue.java b/src/main/java/com/tngtech/configbuilder/annotation/configuration/DoNotLogValue.java
new file mode 100644
index 00000000..5997e9fb
--- /dev/null
+++ b/src/main/java/com/tngtech/configbuilder/annotation/configuration/DoNotLogValue.java
@@ -0,0 +1,17 @@
+package com.tngtech.configbuilder.annotation.configuration;
+
+import com.tngtech.configbuilder.ConfigBuilder;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used to prevent a field's value from being logged
+ * when {@link ConfigBuilder#build(Object...)} builds a config instance.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DoNotLogValue {
+}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/configuration/LoadingOrder.java b/src/main/java/com/tngtech/configbuilder/annotation/configuration/LoadingOrder.java
index 62e7a0da..b30ce509 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/configuration/LoadingOrder.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/configuration/LoadingOrder.java
@@ -2,20 +2,25 @@
import com.tngtech.configbuilder.annotation.valueextractor.CommandLineValue;
import com.tngtech.configbuilder.annotation.valueextractor.DefaultValue;
+import com.tngtech.configbuilder.annotation.valueextractor.EnvironmentVariableValue;
+import com.tngtech.configbuilder.annotation.valueextractor.ImportedValue;
import com.tngtech.configbuilder.annotation.valueextractor.PropertyValue;
+import com.tngtech.configbuilder.annotation.valueextractor.SystemPropertyValue;
+import com.tngtech.configbuilder.annotation.valueextractor.ValueExtractorAnnotation;
import java.lang.annotation.*;
/**
- * This annotation is used to specify the order in which the annotations CommandLineValue, PropertyValue and DefaultValue are processed.
+ * This annotation is used to specify the order in which the {@link ValueExtractorAnnotation} annotations
+ * {@link CommandLineValue}, {@link PropertyValue}, {@link EnvironmentVariableValue},
+ * {@link SystemPropertyValue}, {@link ImportedValue} and {@link DefaultValue} are processed.
* It can specify the order for a certain field if placed on the field, or a global order if placed on the config class.
* The annotations are processed top-down until a string value is found, i.e. the order is from the most important to the least important.
- * The order may only contain ValueExtractorAnnotations, i.e. CommandLineValue.class, PropertyValue.class and DefaultValue.class.
+ * The {@code LoadingOrder} may only contain the aforementioned {@link ValueExtractorAnnotation} classes.
* Usage:@LoadingOrder(value = {PropertyValue.class, CommandLineValue.class, DefaultValue.class})
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoadingOrder {
- public Class extends Annotation>[] value() default {CommandLineValue.class, PropertyValue.class, DefaultValue.class};
-
+ Class extends Annotation>[] value() default {CommandLineValue.class, PropertyValue.class, DefaultValue.class};
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/configuration/PropertyNamePrefix.java b/src/main/java/com/tngtech/configbuilder/annotation/configuration/PropertyNamePrefix.java
new file mode 100644
index 00000000..fe47bbdc
--- /dev/null
+++ b/src/main/java/com/tngtech/configbuilder/annotation/configuration/PropertyNamePrefix.java
@@ -0,0 +1,13 @@
+package com.tngtech.configbuilder.annotation.configuration;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is used to specify additional prefixes to be included in the search for property names
+ * Usage:@PropertyNamePrefix(value = {"test.prefix."})
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PropertyNamePrefix {
+ String[] value() default {""};
+}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyExtension.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyExtension.java
index e6514f75..f3287eb0 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyExtension.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyExtension.java
@@ -13,5 +13,5 @@
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyExtension {
- public String value();
+ String value();
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFilters.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFilters.java
new file mode 100644
index 00000000..c6aa1e12
--- /dev/null
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFilters.java
@@ -0,0 +1,19 @@
+package com.tngtech.configbuilder.annotation.propertyloaderconfiguration;
+
+import com.tngtech.propertyloader.impl.interfaces.PropertyLoaderFilter;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to specify the filters which the PropertyLoader applies to the properties files.
+ * Usage:@PropertyFilters({Config.class})
+ */
+@PropertyLoaderConfigurationAnnotation(PropertyFiltersProcessor.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PropertyFilters {
+ Class extends PropertyLoaderFilter>[] value() default {};
+}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFiltersProcessor.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFiltersProcessor.java
new file mode 100644
index 00000000..e1ca694a
--- /dev/null
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyFiltersProcessor.java
@@ -0,0 +1,46 @@
+package com.tngtech.configbuilder.annotation.propertyloaderconfiguration;
+
+import com.google.common.collect.Maps;
+import com.tngtech.propertyloader.PropertyLoader;
+import com.tngtech.propertyloader.impl.DefaultPropertyFilterContainer;
+import com.tngtech.propertyloader.impl.filters.DecryptingFilter;
+import com.tngtech.propertyloader.impl.filters.EnvironmentResolvingFilter;
+import com.tngtech.propertyloader.impl.filters.ThrowIfPropertyHasToBeDefined;
+import com.tngtech.propertyloader.impl.filters.VariableResolvingFilter;
+import com.tngtech.propertyloader.impl.filters.WarnOnSurroundingWhitespace;
+import com.tngtech.propertyloader.impl.interfaces.PropertyLoaderFilter;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+public class PropertyFiltersProcessor implements PropertyLoaderConfigurationProcessor {
+
+ private interface Action {
+ void execute();
+ }
+
+ public void configurePropertyLoader( Annotation annotation, PropertyLoader propertyLoader ) {
+ DefaultPropertyFilterContainer filterContainer = propertyLoader.getFilters();
+ Map, Action> classActionMap = createFilterMap( filterContainer );
+
+ filterContainer.clear();
+ Class extends PropertyLoaderFilter>[] filters = ((PropertyFilters) annotation).value();
+ for ( Class extends PropertyLoaderFilter> filter : filters ) {
+ if ( classActionMap.containsKey( filter ) ) {
+ classActionMap.get( filter ).execute();
+ } else {
+ throw new IllegalStateException( "unhandled filter class " + filter.getSimpleName() );
+ }
+ }
+ }
+
+ private Map, Action> createFilterMap(DefaultPropertyFilterContainer filterContainer ) {
+ Map, Action> actionMap = Maps.newHashMap();
+ actionMap.put(VariableResolvingFilter.class, filterContainer::withVariableResolvingFilter);
+ actionMap.put(DecryptingFilter.class, filterContainer::withDecryptingFilter);
+ actionMap.put(EnvironmentResolvingFilter.class, filterContainer::withEnvironmentResolvingFilter);
+ actionMap.put(WarnOnSurroundingWhitespace.class, filterContainer::withWarnOnSurroundingWhitespace);
+ actionMap.put(ThrowIfPropertyHasToBeDefined.class, filterContainer::withWarnIfPropertyHasToBeDefined);
+ return actionMap;
+ }
+}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLoaderConfigurationProcessor.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLoaderConfigurationProcessor.java
index 6b3c60b4..b654db51 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLoaderConfigurationProcessor.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLoaderConfigurationProcessor.java
@@ -5,5 +5,5 @@
import java.lang.annotation.Annotation;
public interface PropertyLoaderConfigurationProcessor {
- public void configurePropertyLoader(Annotation annotation, PropertyLoader propertyLoader);
+ void configurePropertyLoader(Annotation annotation, PropertyLoader propertyLoader);
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocations.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocations.java
index 20094685..288ade96 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocations.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocations.java
@@ -13,9 +13,9 @@
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyLocations {
- public String[] directories() default {};
+ String[] directories() default {};
- public Class[] resourcesForClasses() default {};
+ Class[] resourcesForClasses() default {};
- public boolean fromClassLoader() default false;
+ boolean fromClassLoader() default false;
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocationsProcessor.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocationsProcessor.java
index 5b142785..cb8d0757 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocationsProcessor.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertyLocationsProcessor.java
@@ -14,7 +14,7 @@ public void configurePropertyLoader(Annotation annotation, PropertyLoader proper
propertyLoader.atDirectory(location);
}
Class[] classes = ((PropertyLocations) annotation).resourcesForClasses();
- for (Class clazz : classes) {
+ for (Class> clazz : classes) {
propertyLoader.atRelativeToClass(clazz);
}
if (((PropertyLocations) annotation).fromClassLoader()) {
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertySuffixes.java b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertySuffixes.java
index dd83656d..3a339d76 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertySuffixes.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/propertyloaderconfiguration/PropertySuffixes.java
@@ -13,8 +13,7 @@
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertySuffixes {
- public String[] extraSuffixes() default {};
-
- public boolean hostNames() default false;
+ String[] extraSuffixes() default {};
+ boolean hostNames() default false;
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringListTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringListTransformer.java
index 9ad89a6e..ad280fa4 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringListTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringListTransformer.java
@@ -3,18 +3,11 @@
import com.google.common.collect.Lists;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
public class CharacterSeparatedStringToStringListTransformer extends TypeTransformer> {
@Override
public ArrayList transform(String argument) {
-
- ArrayList collection = Lists.newArrayList();
- for (String value : argument.split((String)additionalOptions[0])) {
- collection.add(value);
- }
- return collection;
+ return Lists.newArrayList(argument.split((String)additionalOptions[0]));
}
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringSetTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringSetTransformer.java
index 11e889d6..2a152a95 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringSetTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CharacterSeparatedStringToStringSetTransformer.java
@@ -1,21 +1,13 @@
package com.tngtech.configbuilder.annotation.typetransformer;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Set;
public class CharacterSeparatedStringToStringSetTransformer extends TypeTransformer> {
@Override
public HashSet transform(String argument) {
-
- HashSet collection = Sets.newHashSet();
- for (String value : argument.split((String)additionalOptions[0])) {
- collection.add(value);
- }
- return collection;
+ return Sets.newHashSet(argument.split((String)additionalOptions[0]));
}
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToArrayListTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToArrayListTransformer.java
index 4b504586..5ac0f52c 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToArrayListTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToArrayListTransformer.java
@@ -4,21 +4,17 @@
import com.google.common.collect.Lists;
import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
-public class CollectionToArrayListTransformer extends TypeTransformer {
+public class CollectionToArrayListTransformer extends TypeTransformer {
@Override
public ArrayList transform(Collection argument) {
ArrayList result = Lists.newArrayList();
- for(Object value : argument) {
+ for (Object value : argument) {
result.add(fieldValueTransformer.performNecessaryTransformations(value, ((ParameterizedType) targetType).getActualTypeArguments()[0]));
}
return result;
}
-
-
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToHashSetTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToHashSetTransformer.java
index 6ebe295e..240a9aea 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToHashSetTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/CollectionToHashSetTransformer.java
@@ -6,12 +6,12 @@
import java.util.Collection;
import java.util.HashSet;
-public class CollectionToHashSetTransformer extends TypeTransformer {
+public class CollectionToHashSetTransformer extends TypeTransformer {
@Override
public HashSet transform(Collection argument) {
HashSet result = Sets.newHashSet();
- for(Object value : argument) {
+ for (Object value : argument) {
result.add(fieldValueTransformer.performNecessaryTransformations(value, ((ParameterizedType) targetType).getActualTypeArguments()[0]));
}
return result;
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringCollectionToCommaSeparatedStringTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringCollectionToCommaSeparatedStringTransformer.java
index fbf87c32..06b0b994 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringCollectionToCommaSeparatedStringTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringCollectionToCommaSeparatedStringTransformer.java
@@ -5,10 +5,10 @@
import java.util.Collection;
public class StringCollectionToCommaSeparatedStringTransformer extends TypeTransformer, String> {
-
+
@Override
public String transform(Collection argument) {
- Joiner joiner = Joiner.on((String)additionalOptions[0]);
+ Joiner joiner = Joiner.on((String) additionalOptions[0]);
return joiner.join(argument);
}
}
diff --git a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringOrPrimitiveToPrimitiveTransformer.java b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringOrPrimitiveToPrimitiveTransformer.java
index ec760c1d..e2de48a9 100644
--- a/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringOrPrimitiveToPrimitiveTransformer.java
+++ b/src/main/java/com/tngtech/configbuilder/annotation/typetransformer/StringOrPrimitiveToPrimitiveTransformer.java
@@ -1,23 +1,19 @@
package com.tngtech.configbuilder.annotation.typetransformer;
-
import com.tngtech.configbuilder.exception.PrimitiveParsingException;
-import com.tngtech.configbuilder.exception.TypeTransformerException;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
-import java.lang.reflect.Type;
-public class StringOrPrimitiveToPrimitiveTransformer extends TypeTransformer