├── .checkstyle.xml ├── .codeclimate.yml ├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── maven_jdk11.yml │ └── maven_jdk8.yml ├── .gitignore ├── .idea ├── checkstyle-idea.xml └── vcs.xml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── ch │ └── jalu │ └── configme │ ├── Comment.java │ ├── SettingsHolder.java │ ├── SettingsManager.java │ ├── SettingsManagerBuilder.java │ ├── SettingsManagerImpl.java │ ├── beanmapper │ ├── ConfigMeMapperException.java │ ├── DefaultMapper.java │ ├── ExportName.java │ ├── Mapper.java │ ├── MapperImpl.java │ ├── context │ │ ├── ExportContext.java │ │ ├── ExportContextImpl.java │ │ ├── MappingContext.java │ │ └── MappingContextImpl.java │ ├── leafvaluehandler │ │ ├── EnumLeafType.java │ │ ├── LeafValueHandler.java │ │ ├── LeafValueHandlerImpl.java │ │ └── MapperLeafType.java │ └── propertydescription │ │ ├── BeanDescriptionFactory.java │ │ ├── BeanDescriptionFactoryImpl.java │ │ ├── BeanPropertyComments.java │ │ ├── BeanPropertyDescription.java │ │ └── BeanPropertyDescriptionImpl.java │ ├── configurationdata │ ├── CommentsConfiguration.java │ ├── ConfigurationData.java │ ├── ConfigurationDataBuilder.java │ ├── ConfigurationDataImpl.java │ └── PropertyListBuilder.java │ ├── exception │ └── ConfigMeException.java │ ├── internal │ ├── ConversionUtils.java │ ├── PathUtils.java │ └── StreamUtils.java │ ├── migration │ ├── MigrationService.java │ ├── PlainMigrationService.java │ └── version │ │ ├── VersionMigration.java │ │ └── VersionMigrationService.java │ ├── properties │ ├── ArrayProperty.java │ ├── BaseProperty.java │ ├── BeanProperty.java │ ├── BooleanProperty.java │ ├── DoubleProperty.java │ ├── EnumProperty.java │ ├── EnumSetProperty.java │ ├── FloatProperty.java │ ├── InlineArrayProperty.java │ ├── IntegerProperty.java │ ├── ListProperty.java │ ├── LongProperty.java │ ├── LowercaseStringSetProperty.java │ ├── MapProperty.java │ ├── OptionalProperty.java │ ├── Property.java │ ├── PropertyInitializer.java │ ├── RegexProperty.java │ ├── SetProperty.java │ ├── ShortProperty.java │ ├── StringListProperty.java │ ├── StringProperty.java │ ├── StringSetProperty.java │ ├── TypeBasedProperty.java │ ├── builder │ │ ├── ArrayPropertyBuilder.java │ │ ├── CollectionPropertyBuilder.java │ │ ├── MapPropertyBuilder.java │ │ └── PropertyBuilderUtils.java │ ├── convertresult │ │ ├── ConvertErrorRecorder.java │ │ ├── PropertyValue.java │ │ └── ValueWithComments.java │ └── types │ │ ├── ArrayPropertyType.java │ │ ├── BeanPropertyType.java │ │ ├── BooleanType.java │ │ ├── CollectionPropertyType.java │ │ ├── EnumPropertyType.java │ │ ├── EnumSetPropertyType.java │ │ ├── InlineArrayPropertyType.java │ │ ├── ListPropertyType.java │ │ ├── NumberType.java │ │ ├── PropertyAndLeafType.java │ │ ├── PropertyType.java │ │ ├── RegexType.java │ │ ├── SetPropertyType.java │ │ └── StringType.java │ ├── resource │ ├── MapNormalizer.java │ ├── PropertyPathTraverser.java │ ├── PropertyReader.java │ ├── PropertyResource.java │ ├── YamlFileReader.java │ ├── YamlFileResource.java │ ├── YamlFileResourceOptions.java │ └── yaml │ │ ├── SnakeYamlNodeBuilder.java │ │ ├── SnakeYamlNodeBuilderImpl.java │ │ ├── SnakeYamlNodeContainer.java │ │ └── SnakeYamlNodeContainerImpl.java │ └── utils │ ├── FileUtils.java │ ├── MigrationUtils.java │ └── SettingsHolderClassValidator.java └── test ├── java └── ch │ └── jalu │ └── configme │ ├── BeanDemoTest.java │ ├── ConfigDemoTest.java │ ├── SettingsManagerBuilderTest.java │ ├── SettingsManagerImplTest.java │ ├── TestUtils.java │ ├── beanmapper │ ├── BeanMapOnRootLevelTest.java │ ├── BeanWithCollectionOfBeanTypeTest.java │ ├── BeanWithCustomLeafTypeTest.java │ ├── DefaultMapperTest.java │ ├── MapperExportValueTest.java │ ├── MapperImplCommentRepetitionTest.java │ ├── MapperImplTest.java │ ├── MapperTypeInfoWithNoClassEquivTest.java │ ├── MappingContextImplTest.java │ ├── NestedMapPropertyDemoTest.java │ ├── command │ │ ├── Command.java │ │ ├── CommandConfig.java │ │ ├── ExecutionDetails.java │ │ ├── Executor.java │ │ └── optionalproperties │ │ │ ├── ComplexCommand.java │ │ │ ├── ComplexCommandConfig.java │ │ │ └── ComplexOptionalTypeConfig.java │ ├── context │ │ └── ExportContextTest.java │ ├── leafvaluehandler │ │ ├── EnumLeafTypeTest.java │ │ └── LeafValueHandlerImplTest.java │ ├── migratingbeanmapper │ │ ├── BeanExtensionSettingsHolder.java │ │ ├── BeanExtensionTest.java │ │ └── SingleValueToCollectionMapper.java │ ├── propertydescription │ │ ├── BeanDescriptionFactoryImplTest.java │ │ └── BeanPropertyDescriptionImplTest.java │ ├── typeissues │ │ ├── GenericCollection.java │ │ ├── MapWithNonStringKeys.java │ │ ├── UnsupportedCollection.java │ │ ├── UntypedCollection.java │ │ └── UntypedMap.java │ └── worldgroup │ │ ├── GameMode.java │ │ ├── Group.java │ │ └── WorldGroupConfig.java │ ├── configurationdata │ ├── CommentsConfigurationTest.java │ ├── ConfigurationDataBuilderTest.java │ ├── ConfigurationDataImplTest.java │ ├── PropertyListBuilderTest.java │ ├── PropertyValueTest.java │ └── samples │ │ ├── AdditionalTestConfiguration.java │ │ ├── IllegalSettingsHolderConstructorClasses.java │ │ └── inheritance │ │ ├── ChildInheritanceSettingsHolder.java │ │ ├── MiddleInheritanceSettingsHolder.java │ │ └── TopInheritanceSettingsHolder.java │ ├── demo │ ├── Color.java │ ├── README.md │ ├── TitleConfig.java │ ├── WelcomeWriter.java │ └── beans │ │ ├── BeanPropertiesDemo.java │ │ ├── CoordinateSystem.java │ │ ├── Country.java │ │ ├── DemoSettings.java │ │ ├── Location.java │ │ ├── README.md │ │ ├── User.java │ │ └── UserBase.java │ ├── internal │ ├── ConversionUtilsTest.java │ ├── PathUtilsTest.java │ └── StreamUtilsTest.java │ ├── migration │ ├── PlainMigrationServiceTest.java │ └── version │ │ └── VersionMigrationServiceTest.java │ ├── properties │ ├── ArrayPropertyTest.java │ ├── BasePropertyTest.java │ ├── BeanPropertyTest.java │ ├── BooleanPropertyTest.java │ ├── DoublePropertyTest.java │ ├── EnumPropertyTest.java │ ├── EnumSetPropertyTest.java │ ├── FloatPropertyTest.java │ ├── InlineArrayPropertyTest.java │ ├── IntegerPropertyTest.java │ ├── ListPropertyTest.java │ ├── LongPropertyTest.java │ ├── LowercaseStringSetPropertyTest.java │ ├── MapPropertyTest.java │ ├── OptionalPropertyTest.java │ ├── PropertyInitializerTest.java │ ├── RegexPropertyTest.java │ ├── SetPropertyTest.java │ ├── ShortPropertyTest.java │ ├── StringListPropertyTest.java │ ├── StringPropertyTest.java │ ├── StringSetPropertyTest.java │ ├── TypeBasedPropertyTest.java │ ├── builder │ │ ├── ArrayPropertyBuilderTest.java │ │ ├── CollectionPropertyBuilderTest.java │ │ ├── MapPropertyBuilderTest.java │ │ └── PropertyBuilderUtilsTest.java │ ├── convertresult │ │ └── ValueWithCommentsTest.java │ └── types │ │ ├── ArrayPropertyTypeTest.java │ │ ├── BeanPropertyTypeTest.java │ │ ├── BooleanTypeTest.java │ │ ├── CollectionPropertyTypeTest.java │ │ ├── EnumPropertyTypeTest.java │ │ ├── EnumSetPropertyTypeTest.java │ │ ├── InlineArrayPropertyTypeTest.java │ │ ├── ListPropertyTypeTest.java │ │ ├── NumberTypeTest.java │ │ ├── RegexTypeTest.java │ │ ├── SetPropertyTypeTest.java │ │ └── StringTypeTest.java │ ├── resource │ ├── MapNormalizerTest.java │ ├── PropertyPathTraverserTest.java │ ├── UniqueCommentTest.java │ ├── YamlFileReaderPathsWithNumberTest.java │ ├── YamlFileReaderTest.java │ ├── YamlFileResourceCommentsExportTest.java │ ├── YamlFileResourceEscapingTest.java │ ├── YamlFileResourceMultilineStringTest.java │ ├── YamlFileResourceNewLineTest.java │ ├── YamlFileResourceNoSplitPathsTest.java │ ├── YamlFileResourceOptionalInBeanPropertyTest.java │ ├── YamlFileResourceOptionsTest.java │ ├── YamlFileResourceRootMapPropertyTest.java │ ├── YamlFileResourceTest.java │ ├── YamlFileResourceTopCommentTest.java │ ├── YamlSetPropertyExportTest.java │ ├── rootcommentsamples │ │ ├── GroupPropertyHolder.java │ │ └── TestConfig.java │ └── yaml │ │ ├── SnakeYamlNodeBuilderImplTest.java │ │ └── SnakeYamlNodeContainerImplTest.java │ ├── samples │ ├── ClassWithPrivatePropertyField.java │ ├── TestConfiguration.java │ ├── TestEnum.java │ ├── TestVersionConfiguration.java │ ├── beanannotations │ │ ├── AnnotatedEntry.java │ │ ├── BeanWithEmptyName.java │ │ ├── BeanWithExportName.java │ │ ├── BeanWithExportNameExtension.java │ │ └── BeanWithNameClash.java │ ├── inheritance │ │ ├── Child.java │ │ ├── Middle.java │ │ └── Parent.java │ └── settingsholders │ │ ├── FullyValidSettingsHolder1.java │ │ ├── FullyValidSettingsHolder2.java │ │ ├── MissingCommentsHolder.java │ │ ├── SettingsHolderWithEnumPropertyComments.java │ │ ├── SettingsHolderWithInvalidConstants.java │ │ └── SettingsHolderWithVariousCommentLengths.java │ └── utils │ ├── FileUtilsTest.java │ ├── MigrationUtilsTest.java │ └── SettingsHolderClassValidatorTest.java └── resources ├── beanmapper ├── commands.yml ├── commands_invalid.yml ├── commands_invalid_2.yml ├── commands_root_path.yml ├── nested_chat_component.yml ├── nested_chat_component_complex_expected.yml ├── optionalproperties │ └── complex-commands.yml ├── typeissues │ ├── collectionconfig.yml │ └── mapconfig.yml ├── worlds.yml └── worlds_invalid.yml ├── charsets ├── iso-8859-1_sample.yml └── utf8_sample.yml ├── config-difficult-values.yml ├── config-export-expected.yml ├── config-incomplete-sample.yml ├── config-sample.yml ├── configurationfiles ├── config-with-chars-to-escape.yml └── config-with-number-paths.yml ├── demo ├── bean_demo_config.yml └── config.yml ├── empty_file.yml ├── multiple_lines.yml └── versions └── config-old-version-sample.yml /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: '2' # required to adjust maintainability checks 2 | 3 | plugins: 4 | checkstyle: 5 | enabled: true 6 | channel: 'checkstyle-10-7-0' 7 | config: 8 | file: '.checkstyle.xml' 9 | 10 | checks: 11 | # We disable all the following CodeClimate checks: Checkstyle already checks for these things and has the advantage 12 | # that the Checkstyle config can also be used in one's IDE. 13 | argument-count: 14 | enabled: false 15 | complex-logic: 16 | enabled: false 17 | file-lines: 18 | enabled: false 19 | method-complexity: 20 | enabled: false 21 | method-count: 22 | enabled: false 23 | method-lines: 24 | enabled: false 25 | nested-control-flow: 26 | enabled: false 27 | return-statements: 28 | enabled: false 29 | 30 | # No Checkstyle equivalent, but it keeps reporting false positives because of similar constructors and imports 31 | similar-code: 32 | enabled: false 33 | # No Checkstyle equivalent, so enabled as long as it's not full of false positives 34 | identical-code: 35 | enabled: true 36 | 37 | exclude_patterns: 38 | # Don't check test scope 39 | - 'src/test/java/**' 40 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | # Set the charset, and space indention 10 | [*.java] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.java text eol=lf 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | target-branch: dependencies 9 | ignore: 10 | - dependency-name: "org.mockito:mockito-core" 11 | versions: ">= 5" 12 | - dependency-name: "org.mockito:mockito-junit-jupiter" 13 | versions: ">= 5" 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: daily 18 | target-branch: master 19 | -------------------------------------------------------------------------------- /.github/workflows/maven_jdk11.yml: -------------------------------------------------------------------------------- 1 | # Secondary build that builds the project with JDK 11. Note that the target in the pom.xml is still Java 8. 2 | 3 | name: Java 11 build 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up JDK 11 13 | uses: actions/setup-java@v4 14 | with: 15 | java-version: '11' 16 | distribution: 'adopt' 17 | - name: Build with Maven 18 | run: mvn -B --file pom.xml package 19 | -------------------------------------------------------------------------------- /.github/workflows/maven_jdk8.yml: -------------------------------------------------------------------------------- 1 | # Builds the project with Java 8. 2 | 3 | name: Java 8 build 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | env: 10 | coveralls_repo_token: ${{ secrets.COVERALLS_REPO_TOKEN }} 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: Set up JDK 8 16 | uses: actions/setup-java@v4 17 | with: 18 | java-version: '8' 19 | distribution: 'adopt' 20 | 21 | - name: Build with Maven 22 | run: mvn -B --file pom.xml package jacoco:report 23 | 24 | - name: Coveralls 25 | uses: coverallsapp/github-action@v2 26 | if: github.event_name != 'pull_request' 27 | with: 28 | base-path: src/main/java 29 | # The file is optional, but the documentation says it's better to specify it. 30 | file: target/site/jacoco/jacoco.xml 31 | 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java files ### 2 | *.class 3 | 4 | # Package Files 5 | #*.jar 6 | *.war 7 | *.ear 8 | 9 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 10 | hs_err_pid* 11 | 12 | 13 | 14 | ### Intellij ### 15 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 16 | # Ignore project files 17 | *.iml 18 | 19 | # Ignore IDEA directory 20 | .idea/* 21 | !.idea/vcs.xml 22 | !.idea/checkstyle-idea.xml 23 | 24 | # File-based project format: 25 | *.ipr 26 | *.iws 27 | 28 | ### Plugin-specific files: ### 29 | # IntelliJ 30 | /out/ 31 | 32 | # mpeltonen/sbt-idea plugin 33 | .idea_modules/ 34 | 35 | # JIRA plugin 36 | atlassian-ide-plugin.xml 37 | 38 | # Crashlytics plugin (for Android Studio and IntelliJ) 39 | com_crashlytics_export_strings.xml 40 | crashlytics.properties 41 | crashlytics-build.properties 42 | 43 | 44 | 45 | ### Eclipse ### 46 | *.pydevproject 47 | .metadata 48 | .gradle 49 | bin/ 50 | tmp/ 51 | *.tmp 52 | *.bak 53 | *.swp 54 | *~.nib 55 | local.properties 56 | .settings/ 57 | .loadpath 58 | 59 | # Eclipse Core 60 | .project 61 | 62 | # External tool builders 63 | .externalToolBuilders/ 64 | 65 | # Locally stored "Eclipse launch configurations" 66 | *.launch 67 | 68 | # CDT-specific 69 | .cproject 70 | 71 | # JDT-specific (Eclipse Java Development Tools) 72 | .classpath 73 | 74 | # PDT-specific 75 | .buildpath 76 | 77 | # sbteclipse plugin 78 | .target 79 | 80 | # TeXlipse plugin 81 | .texlipse 82 | 83 | 84 | 85 | ### Maven ### 86 | target/ 87 | pom.xml.tag 88 | pom.xml.releaseBackup 89 | pom.xml.versionsBackup 90 | pom.xml.next 91 | release.properties 92 | dependency-reduced-pom.xml 93 | buildNumber.properties 94 | 95 | 96 | 97 | ### NetBeans ### 98 | nbproject/private/ 99 | build/ 100 | nbbuild/ 101 | dist/ 102 | nbdist/ 103 | nbactions.xml 104 | nb-configuration.xml 105 | .nb-gradle/ 106 | 107 | 108 | 109 | ### Git ### 110 | # Don't exclude the .gitignore itself 111 | !.gitignore 112 | -------------------------------------------------------------------------------- /.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10.7.0 5 | JavaOnly 6 | true 7 | true 8 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 The AuthMe Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/Comment.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Comment for properties which are also included in the configuration file upon saving. This annotation can be used on 12 | * {@link ch.jalu.configme.properties.Property Property} fields, as well as on the fields of 13 | * bean classes that are used for {@link ch.jalu.configme.properties.BeanProperty bean properties}. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.FIELD) 17 | public @interface Comment { 18 | 19 | /** 20 | * Defines the comment to associate with a property field. You can define an empty line with no comment marker 21 | * ('#' in YAML) by adding a line that is just "\n", e.g. {@code @Comment("Title", "\n", "Lorem ipsum")}. 22 | * 23 | * @return the comment to associate with the property 24 | */ 25 | String @NotNull [] value(); 26 | 27 | /** 28 | * Defines if the comment should be repeated, or if it should only be included in the output the first time. 29 | * This method is relevant only for bean properties: if a bean class used in a collection has comments, 30 | * the comments will either be included on the first entry if {@code false}, or on each entry if {@code true}. 31 | * 32 | * @return whether the comment should be repeated for each occurrence of the same field 33 | */ 34 | boolean repeat() default false; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/SettingsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme; 2 | 3 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Marker interface for classes that define Property objects. 8 | *

9 | * Declare your properties as {@code public static final} fields 10 | * of {@link ch.jalu.configme.properties.Property} type in a class 11 | * which implements this interface. 12 | *

13 | * Classes implementing this interface must have a no-args constructor (any visibility). 14 | * 15 | * @see ch.jalu.configme.properties.PropertyInitializer 16 | * @see ch.jalu.configme.configurationdata.ConfigurationDataBuilder 17 | */ 18 | public interface SettingsHolder { 19 | 20 | /** 21 | * Allows to register comments for sections and properties by overriding this method and interacting 22 | * with the given configuration object. 23 | *

24 | * Note that comments can also be put on Property fields with the {@link Comment} annotation. 25 | * 26 | * @param conf the comments configuration 27 | */ 28 | default void registerComments(@NotNull CommentsConfiguration conf) { 29 | // override to register comments for sections 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/SettingsManager.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme; 2 | 3 | import ch.jalu.configme.migration.MigrationService; 4 | import ch.jalu.configme.properties.Property; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Settings manager. 9 | *

10 | * The settings manager manages a {@link ch.jalu.configme.resource.PropertyResource property resource}, 11 | * {@link ch.jalu.configme.configurationdata.ConfigurationData configuration data}, and an optional 12 | * {@link MigrationService migration service}. 13 | *

14 | * The settings manager allows to look up and modify properties. After it is initialized, the settings manager 15 | * should be the only class from ConfigMe that developers need to interact with. 16 | * 17 | * @see ConfigMe on Github 18 | * @see SettingsManagerBuilder 19 | */ 20 | public interface SettingsManager { 21 | 22 | /** 23 | * Gets the given property from the configuration. 24 | * 25 | * @param property the property to retrieve 26 | * @param the property's type 27 | * @return the property's value 28 | */ 29 | @NotNull T getProperty(@NotNull Property property); 30 | 31 | /** 32 | * Sets a new value for the given property. 33 | * 34 | * @param property the property to modify 35 | * @param value the new value to assign to the property 36 | * @param the property's type 37 | */ 38 | void setProperty(@NotNull Property property, @NotNull T value); 39 | 40 | /** 41 | * Reloads the configuration from the property resource. 42 | */ 43 | void reload(); 44 | 45 | /** 46 | * Saves the properties to the configuration file. 47 | */ 48 | void save(); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/ConfigMeMapperException.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper; 2 | 3 | import ch.jalu.configme.beanmapper.context.MappingContext; 4 | import ch.jalu.configme.exception.ConfigMeException; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Exception during a bean mapping process. 10 | */ 11 | public class ConfigMeMapperException extends ConfigMeException { 12 | 13 | private static final long serialVersionUID = 5439842847683269906L; 14 | 15 | /** 16 | * Constructor. 17 | * 18 | * @param message the exception message 19 | */ 20 | public ConfigMeMapperException(@NotNull String message) { 21 | super(message); 22 | } 23 | 24 | /** 25 | * Constructor. 26 | * 27 | * @param message the exception message 28 | * @param cause the cause 29 | */ 30 | public ConfigMeMapperException(@NotNull String message, @Nullable Throwable cause) { 31 | super(message, cause); 32 | } 33 | 34 | /** 35 | * Constructor. 36 | * 37 | * @param mappingContext the mapping context with which the message should be extended 38 | * @param message basic message to extend 39 | */ 40 | public ConfigMeMapperException(@NotNull MappingContext mappingContext, @NotNull String message) { 41 | super(constructMessage(mappingContext, message)); 42 | } 43 | 44 | /** 45 | * Constructor. 46 | * 47 | * @param mappingContext the mapping context with which the message should be extended 48 | * @param message basic message to extend 49 | * @param cause the cause 50 | */ 51 | public ConfigMeMapperException(@NotNull MappingContext mappingContext, @NotNull String message, 52 | @Nullable Throwable cause) { 53 | super(constructMessage(mappingContext, message), cause); 54 | } 55 | 56 | private static @NotNull String constructMessage(@NotNull MappingContext mappingContext, @NotNull String message) { 57 | return message + ", for mapping of: [" + mappingContext.createDescription() + "]"; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/DefaultMapper.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Provides the {@link Mapper} instance which is used by default. 7 | */ 8 | public final class DefaultMapper extends MapperImpl { 9 | 10 | private static DefaultMapper instance; 11 | 12 | private DefaultMapper() { 13 | } 14 | 15 | /** 16 | * @return default mapper instance 17 | */ 18 | public static @NotNull Mapper getInstance() { 19 | if (instance == null) { 20 | instance = new DefaultMapper(); 21 | } 22 | return instance; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/ExportName.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * Annotation placed on a field to indicate that it should be loaded and written 13 | * to a property resource with a different name. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.FIELD) 17 | @Documented 18 | public @interface ExportName { 19 | 20 | /** 21 | * @return the name to use when interacting with property resources 22 | */ 23 | @NotNull String value(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/Mapper.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.typeresolver.TypeInfo; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Creates JavaBeans based on the values coming from a property reader. See the JavaDoc on the default implementation, 10 | * {@link MapperImpl}, for more details. 11 | */ 12 | public interface Mapper { 13 | 14 | /** 15 | * Creates an object of the given type from the given value. Returns null if the 16 | * conversion is not possible. The value usually stems from a property resource and 17 | * is a Map of values. 18 | * 19 | * @param value the value to convert (typically a Map) 20 | * @param targetType the required type 21 | * @param errorRecorder error recorder to register errors even if a valid value is returned 22 | * @return object of the given type, or null if not possible 23 | */ 24 | @Nullable Object convertToBean(@Nullable Object value, @NotNull TypeInfo targetType, 25 | @NotNull ConvertErrorRecorder errorRecorder); 26 | 27 | /** 28 | * Converts the given value to an object of the given class, if possible. Returns null otherwise. 29 | * This is a convenience method as typed alternative to 30 | * {@link #convertToBean(Object, TypeInfo, ConvertErrorRecorder)}. 31 | * 32 | * @param value the value to convert (typically a Map) 33 | * @param clazz the required class 34 | * @param errorRecorder error recorder to register errors even if a valid value is returned 35 | * @param the class type 36 | * @return object of the given type, or null if not possible 37 | */ 38 | @SuppressWarnings("unchecked") 39 | default @Nullable T convertToBean(@Nullable Object value, @NotNull Class clazz, 40 | @NotNull ConvertErrorRecorder errorRecorder) { 41 | return (T) convertToBean(value, new TypeInfo(clazz), errorRecorder); 42 | } 43 | 44 | /** 45 | * Converts a complex type such as a JavaBean object to simple types suitable for exporting. This method 46 | * typically returns a Map of values, or simple types like String / Number for scalar values. 47 | * Used in the {@link ch.jalu.configme.properties.BeanProperty#toExportValue} method. 48 | * 49 | * @param object the object to convert to its export value 50 | * @return export value to use 51 | */ 52 | @Nullable Object toExportValue(@NotNull Object object); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/context/ExportContext.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.context; 2 | 3 | import ch.jalu.configme.beanmapper.propertydescription.BeanPropertyComments; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Context used by the bean mapper when a value is exported. 8 | */ 9 | public interface ExportContext { 10 | 11 | /** 12 | * @return path relative to the bean root that is currently being processed 13 | */ 14 | @NotNull String getBeanPath(); 15 | 16 | /** 17 | * Creates a child context with the given path as addition to this context's path. 18 | * 19 | * @param path the path to add 20 | * @return child export context 21 | */ 22 | @NotNull ExportContext createChildContext(@NotNull String path); 23 | 24 | /** 25 | * Specifies whether the given comments instance should be included in the export in this context. Comments 26 | * should not be included if they're specified to appear only once and they've already been incorporated. 27 | * 28 | * @param comments the comments instance to process 29 | * @return true if the comments should be included, false if they should be skipped 30 | */ 31 | boolean shouldInclude(@NotNull BeanPropertyComments comments); 32 | 33 | /** 34 | * Registers the given comments. Used to keep track of all unique comment's UUIDs that have been processed. 35 | * 36 | * @param comments the comments instance to process 37 | */ 38 | void registerComment(@NotNull BeanPropertyComments comments); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/context/ExportContextImpl.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.context; 2 | 3 | import ch.jalu.configme.beanmapper.propertydescription.BeanPropertyComments; 4 | import ch.jalu.configme.internal.PathUtils; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | import java.util.UUID; 11 | 12 | /** 13 | * Standard implementation of {@link ExportContext}. 14 | */ 15 | public class ExportContextImpl implements ExportContext { 16 | 17 | private final String beanPath; 18 | private final Set usedUniqueCommentIds; 19 | 20 | /** 21 | * Constructor. 22 | * 23 | * @param beanPath path relative to the bean root 24 | * @param usedUniqueCommentIds set of unique comment UUIDs that have already been used 25 | */ 26 | protected ExportContextImpl(@NotNull String beanPath, @NotNull Set usedUniqueCommentIds) { 27 | this.beanPath = beanPath; 28 | this.usedUniqueCommentIds = usedUniqueCommentIds; 29 | } 30 | 31 | /** 32 | * Creates an initial context for the export of a bean value. 33 | * 34 | * @return root export context 35 | */ 36 | public static @NotNull ExportContextImpl createRoot() { 37 | return new ExportContextImpl("", new HashSet<>()); 38 | } 39 | 40 | @Override 41 | public @NotNull ExportContext createChildContext(@NotNull String path) { 42 | String childPath = PathUtils.concatSpecifierAware(beanPath, path); 43 | return new ExportContextImpl(childPath, usedUniqueCommentIds); 44 | } 45 | 46 | @Override 47 | public @NotNull String getBeanPath() { 48 | return beanPath; 49 | } 50 | 51 | @Override 52 | public boolean shouldInclude(@NotNull BeanPropertyComments comments) { 53 | return !comments.getComments().isEmpty() 54 | && (comments.getUuid() == null || !usedUniqueCommentIds.contains(comments.getUuid())); 55 | } 56 | 57 | @Override 58 | public void registerComment(@NotNull BeanPropertyComments comments) { 59 | if (comments.getUuid() != null) { 60 | usedUniqueCommentIds.add(comments.getUuid()); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/context/MappingContextImpl.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.context; 2 | 3 | import ch.jalu.configme.internal.PathUtils; 4 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 5 | import ch.jalu.typeresolver.TypeInfo; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Standard implementation of {@link MappingContext}. 10 | */ 11 | public class MappingContextImpl implements MappingContext { 12 | 13 | private final String beanPath; 14 | private final TypeInfo targetType; 15 | private final ConvertErrorRecorder errorRecorder; 16 | 17 | protected MappingContextImpl(@NotNull String beanPath, @NotNull TypeInfo targetType, 18 | @NotNull ConvertErrorRecorder errorRecorder) { 19 | this.beanPath = beanPath; 20 | this.targetType = targetType; 21 | this.errorRecorder = errorRecorder; 22 | } 23 | 24 | /** 25 | * Creates an initial context (used at the start of a mapping process). 26 | * 27 | * @param targetType the required type 28 | * @param errorRecorder error recorder to register errors even if a valid value is returned 29 | * @return root mapping context 30 | */ 31 | public static @NotNull MappingContextImpl createRoot(@NotNull TypeInfo targetType, 32 | @NotNull ConvertErrorRecorder errorRecorder) { 33 | return new MappingContextImpl("", targetType, errorRecorder); 34 | } 35 | 36 | @Override 37 | public @NotNull MappingContext createChild(@NotNull String subPath, @NotNull TypeInfo targetType) { 38 | String childPath = PathUtils.concatSpecifierAware(beanPath, subPath); 39 | return new MappingContextImpl(childPath, targetType, errorRecorder); 40 | } 41 | 42 | public @NotNull String getBeanPath() { 43 | return beanPath; 44 | } 45 | 46 | @Override 47 | public @NotNull TypeInfo getTargetType() { 48 | return targetType; 49 | } 50 | 51 | @Override 52 | public @NotNull String createDescription() { 53 | return "Bean path: '" + beanPath + "', type: '" + targetType.getType() + "'"; 54 | } 55 | 56 | @Override 57 | public @NotNull ConvertErrorRecorder getErrorRecorder() { 58 | return errorRecorder; 59 | } 60 | 61 | @Override 62 | public @NotNull String toString() { 63 | return getClass().getSimpleName() + "[" + createDescription() + "]"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/leafvaluehandler/EnumLeafType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.leafvaluehandler; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.typeresolver.EnumUtils; 5 | import ch.jalu.typeresolver.TypeInfo; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * Handles enum type conversions for the bean mapper. 11 | */ 12 | public class EnumLeafType implements MapperLeafType { 13 | 14 | @Override 15 | public @Nullable Object convert(@Nullable Object value, @NotNull TypeInfo targetType, 16 | @NotNull ConvertErrorRecorder errorRecorder) { 17 | if (value instanceof String) { 18 | return EnumUtils.asEnumClassIfPossible(targetType.toClass()) 19 | .flatMap(clz -> EnumUtils.tryValueOfCaseInsensitive(clz, (String) value)) 20 | .orElse(null); 21 | } 22 | return null; 23 | } 24 | 25 | @Override 26 | public @Nullable Object toExportValueIfApplicable(@Nullable Object value) { 27 | if (value instanceof Enum) { 28 | return ((Enum) value).name(); 29 | } 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/leafvaluehandler/LeafValueHandler.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.leafvaluehandler; 2 | 3 | import ch.jalu.configme.beanmapper.context.ExportContext; 4 | import ch.jalu.configme.beanmapper.context.MappingContext; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * The leaf value handler is used in {@link ch.jalu.configme.beanmapper.MapperImpl} to convert "simple" values that 10 | * were read from a resource to its desired type. 11 | *

12 | * The bean mapper handles complex types such as maps and collections, and recursively calls the bean mapping process 13 | * accordingly. This class complements the mapper by halting this process and providing "leaf values" to be set into 14 | * Java beans. 15 | *

16 | * The default implementation is {@link LeafValueHandlerImpl}. With the aid of {@link MapperLeafType} entries, it 17 | * provides conversions for the leaf types it supports. To implement additional conversions, implement your own 18 | * {@link MapperLeafType} implementations and add them to {@link LeafValueHandlerImpl}. Alternatively, you can create 19 | * your own implementation of this interface if you need more control over the conversion process. 20 | */ 21 | public interface LeafValueHandler { 22 | 23 | /** 24 | * Converts the given value to the target type (as defined by the mapping context), if supported. Otherwise, 25 | * null is returned. If a value is returned, its type is guaranteed to match the target type. 26 | * 27 | * @param value the value to convert (read from a property resource) 28 | * @param mappingContext mapping context with the target type 29 | * @return the converted value, or null if not applicable 30 | */ 31 | @Nullable Object convert(@Nullable Object value, @NotNull MappingContext mappingContext); 32 | 33 | /** 34 | * Converts the value of a property to a value suitable for exporting. This method converts the opposite 35 | * way of {@link #convert}. Null is returned if this leaf value handler does not support the object's type. 36 | * 37 | * @param value the value to convert 38 | * @param exportContext the export context (usually not needed) 39 | * @return the value suitable for exporting, or null if not applicable 40 | */ 41 | @Nullable Object toExportValue(@Nullable Object value, @NotNull ExportContext exportContext); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/leafvaluehandler/MapperLeafType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.leafvaluehandler; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.typeresolver.TypeInfo; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * A leaf type represents a "simple" type like a String or a number. Used by the bean mapper's 10 | * {@link LeafValueHandlerImpl}, a leaf type provides a simple conversion for a specific type. 11 | * 12 | * @see LeafValueHandler 13 | */ 14 | public interface MapperLeafType { 15 | 16 | /** 17 | * Converts the given value to the specified target type, if possible. Returns null otherwise. 18 | * This method must either return {@code null} or an object of the given target type. 19 | * 20 | * @param value the value to convert 21 | * @param targetType the required type 22 | * @param errorRecorder error recorder to register errors even if a valid value is returned 23 | * @return value of the given type, or null if not applicable 24 | */ 25 | @Nullable Object convert(@Nullable Object value, @NotNull TypeInfo targetType, 26 | @NotNull ConvertErrorRecorder errorRecorder); 27 | 28 | /** 29 | * Converts the given value to a type suitable for exporting. Used by the mapper 30 | * when {@link ch.jalu.configme.beanmapper.MapperImpl#toExportValue(Object)} is called. 31 | * Returns null if the leaf value handler cannot handle the value. 32 | *

33 | * Return {@link ch.jalu.configme.beanmapper.MapperImpl#RETURN_NULL} to signal that null should be used 34 | * as the export value (returning {@code null} itself means this leaf value handler cannot handle it). 35 | * 36 | * @param value the value to convert to an export value, if possible 37 | * @return value to use in the export, or null if not applicable 38 | */ 39 | @Nullable Object toExportValueIfApplicable(@Nullable Object value); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/propertydescription/BeanDescriptionFactory.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.propertydescription; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * Factory which analyzes a class and returns all writable properties. 9 | *

10 | * Default implementation: {@link BeanDescriptionFactoryImpl}. 11 | */ 12 | public interface BeanDescriptionFactory { 13 | 14 | /** 15 | * Returns all properties on the given class which should be considered while creating a bean of the 16 | * given type. This is usually all properties which can be read from and written to. 17 | * 18 | * @param clazz the class whose properties should be returned 19 | * @return the relevant properties on the class 20 | */ 21 | @NotNull Collection getAllProperties(@NotNull Class clazz); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/propertydescription/BeanPropertyComments.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.propertydescription; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.UUID; 9 | 10 | /** 11 | * Contains the comments for a bean property, with a UUID if the comment should only be included once. 12 | */ 13 | public class BeanPropertyComments { 14 | 15 | /** Instance which can be used if there are no comments to add. */ 16 | public static final BeanPropertyComments EMPTY = new BeanPropertyComments(Collections.emptyList(), null); 17 | 18 | private final List comments; 19 | private final UUID uuid; 20 | 21 | /** 22 | * Constructor. 23 | * 24 | * @param comments the comments 25 | * @param uuid UUID to identify the comment with, null if the comment should be repeated 26 | */ 27 | public BeanPropertyComments(@NotNull List comments, @Nullable UUID uuid) { 28 | this.comments = comments; 29 | this.uuid = uuid; 30 | } 31 | 32 | public @NotNull List getComments() { 33 | return comments; 34 | } 35 | 36 | /** 37 | * UUID to identify this comment. Not-null when the comment should not be repeated if it could be part of the 38 | * export multiple times. 39 | * 40 | * @return UUID if the comment should be unique, null otherwise 41 | */ 42 | public @Nullable UUID getUuid() { 43 | return uuid; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/beanmapper/propertydescription/BeanPropertyDescription.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.propertydescription; 2 | 3 | import ch.jalu.typeresolver.TypeInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | /** 8 | * Represents a property within a bean class, as used in {@link ch.jalu.configme.beanmapper.MapperImpl}. 9 | * There, for instance, there is a {@link BeanDescriptionFactory} field responsible for creating bean descriptions. 10 | *

11 | * Default implementation is {@link BeanPropertyDescriptionImpl}. 12 | */ 13 | public interface BeanPropertyDescription { 14 | 15 | /** 16 | * @return the name of the property in the configuration file 17 | */ 18 | @NotNull String getName(); 19 | 20 | /** 21 | * @return property type 22 | */ 23 | @NotNull TypeInfo getTypeInformation(); 24 | 25 | /** 26 | * Sets the given value on the provided bean for this property. The value should correspond 27 | * to the {@link #getTypeInformation() property type}. 28 | * 29 | * @param bean the bean to set the property on 30 | * @param value the value to set 31 | */ 32 | void setValue(@NotNull Object bean, @NotNull Object value); 33 | 34 | /** 35 | * Returns the value of the property for the given bean. 36 | * 37 | * @param bean the bean to read the property from 38 | * @return the value of the property (can be null) 39 | */ 40 | @Nullable Object getValue(@NotNull Object bean); 41 | 42 | /** 43 | * @return the comments associated with this property 44 | */ 45 | @NotNull BeanPropertyComments getComments(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/configurationdata/CommentsConfiguration.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.UnmodifiableView; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collections; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * Allows to register comments (intended via {@link SettingsHolder#registerComments}). 16 | */ 17 | public class CommentsConfiguration { 18 | 19 | private final @NotNull Map> comments; 20 | 21 | /** 22 | * Constructor. 23 | */ 24 | public CommentsConfiguration() { 25 | this.comments = new HashMap<>(); 26 | } 27 | 28 | /** 29 | * Constructor. 30 | * 31 | * @param comments map to store comments in 32 | */ 33 | public CommentsConfiguration(@NotNull Map> comments) { 34 | this.comments = comments; 35 | } 36 | 37 | /** 38 | * Sets the given lines for the provided path, overriding any previously existing comments for the path. 39 | * An entry that is a sole new-line (i.e. "\n") will result in an empty line without any comment marker. 40 | * 41 | * @param path the path to register the comment lines for 42 | * @param commentLines the comment lines to set for the path 43 | */ 44 | public void setComment(@NotNull String path, @NotNull String... commentLines) { 45 | List replaced = comments.put(path, Collections.unmodifiableList(Arrays.asList(commentLines))); 46 | 47 | if (replaced != null) { 48 | String commentAnnotation = "@" + Comment.class.getSimpleName(); 49 | throw new IllegalStateException("Comments for path '" + path + "' have already been registered. Use " 50 | + commentAnnotation + " on a property field, or one call to CommentsConfiguration#setComment per path"); 51 | } 52 | } 53 | 54 | /** 55 | * Returns a read-only view of the map with all comments. 56 | * 57 | * @return map with all comments 58 | */ 59 | public @NotNull @UnmodifiableView Map> getAllComments() { 60 | return Collections.unmodifiableMap(comments); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/exception/ConfigMeException.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.exception; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * ConfigMe exception. 8 | */ 9 | public class ConfigMeException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = -865062331853823084L; 12 | 13 | public ConfigMeException(@NotNull String message) { 14 | super(message); 15 | } 16 | 17 | public ConfigMeException(@NotNull String message, @Nullable Throwable cause) { 18 | super(message, cause); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/internal/StreamUtils.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.internal; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.stream.IntStream; 6 | import java.util.stream.Stream; 7 | 8 | /** 9 | * Stream utils. 10 | */ 11 | public final class StreamUtils { 12 | 13 | private StreamUtils() { 14 | } 15 | 16 | /** 17 | * Creates a stream with the requested size. Every element in the stream is the given {@code element}. 18 | * 19 | * @param element the element to repeat 20 | * @param numberOfTimes number of times the stream should have the element 21 | * @param element type 22 | * @return stream with the element the requested number of times 23 | */ 24 | public static @NotNull Stream repeat(@NotNull T element, int numberOfTimes) { 25 | return IntStream.range(0, numberOfTimes) 26 | .mapToObj(i -> element); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/migration/MigrationService.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.migration; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * The migration service is called when the settings manager is instantiated. It allows to 9 | * validate the settings and perform migrations (e.g. delete old settings, rename settings). 10 | * If a migration is performed, the config file will be saved again. 11 | */ 12 | public interface MigrationService { 13 | 14 | /** Constant for the return value of {@link #checkAndMigrate}, indicating that a migration has been performed. */ 15 | boolean MIGRATION_REQUIRED = true; 16 | 17 | /** Constant for the return value of {@link #checkAndMigrate}, indicating that no migration was needed. */ 18 | boolean NO_MIGRATION_NEEDED = false; 19 | 20 | /** 21 | * Performs the migration, returning whether a migration has been performed or not. 22 | * 23 | * @param reader reader to access the values in the configuration file 24 | * @param configurationData configuration data, which knows all properties and manages their associated values 25 | * @return true if a migration has been performed, false otherwise. Indicates whether the configuration data should 26 | * be saved to the configuration file or not 27 | */ 28 | boolean checkAndMigrate(@NotNull PropertyReader reader, @NotNull ConfigurationData configurationData); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/migration/PlainMigrationService.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.migration; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Simple migration service that can be extended. 9 | */ 10 | public class PlainMigrationService implements MigrationService { 11 | 12 | @Override 13 | public boolean checkAndMigrate(@NotNull PropertyReader reader, @NotNull ConfigurationData configurationData) { 14 | if (performMigrations(reader, configurationData) == MIGRATION_REQUIRED 15 | || !configurationData.areAllValuesValidInResource()) { 16 | return MIGRATION_REQUIRED; 17 | } 18 | return NO_MIGRATION_NEEDED; 19 | } 20 | 21 | /** 22 | * Override this method for custom migrations. This method is executed before checking 23 | * if all settings are present. For instance, you could implement deleting obsolete properties 24 | * and rename properties in this method. 25 | *

26 | * Note that the settings manager automatically saves the resource 27 | * if the migration service returns {@link #MIGRATION_REQUIRED} from {@link #checkAndMigrate}. 28 | * 29 | * @param reader the reader with which the configuration file can be read 30 | * @param configurationData the configuration data 31 | * @return true if a migration has been performed, false otherwise (see constants on {@link MigrationService}) 32 | */ 33 | protected boolean performMigrations(@NotNull PropertyReader reader, @NotNull ConfigurationData configurationData) { 34 | return NO_MIGRATION_NEEDED; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/migration/version/VersionMigration.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.migration.version; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * A migration used by {@link VersionMigrationService} to migrate from one configuration version to a newer one. 9 | * 10 | * @see VersionMigrationService 11 | */ 12 | public interface VersionMigration { 13 | 14 | /** 15 | * @return the configuration version this migration converts from (e.g. 1) 16 | */ 17 | int fromVersion(); 18 | 19 | /** 20 | * @return the configuration version this migration converts to (e.g. 2) 21 | */ 22 | int targetVersion(); 23 | 24 | /** 25 | * Migrates the configuration. 26 | * 27 | * @param reader the property reader to read the configuration file from 28 | * @param configurationData configuration data to update a property's value 29 | */ 30 | void migrate(@NotNull PropertyReader reader, @NotNull ConfigurationData configurationData); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/ArrayProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.ArrayPropertyType; 4 | import ch.jalu.configme.properties.types.PropertyType; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.function.IntFunction; 8 | 9 | /** 10 | * Property whose value is an array of a given type. 11 | * 12 | * @param the type of the elements in the array 13 | */ 14 | public class ArrayProperty extends TypeBasedProperty { 15 | 16 | /** 17 | * Constructor. 18 | * 19 | * @param path the path of the property 20 | * @param entryType the property type the elements of the arrays have 21 | * @param arrayProducer array constructor (desired array size as argument) 22 | * @param defaultValue the default value of the property 23 | */ 24 | public ArrayProperty(@NotNull String path, @NotNull PropertyType entryType, 25 | @NotNull IntFunction arrayProducer, T @NotNull [] defaultValue) { 26 | this(path, new ArrayPropertyType<>(entryType, arrayProducer), defaultValue); 27 | } 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param path the path of the property 33 | * @param type the type of this property (e.g. {@link ArrayPropertyType}) 34 | * @param defaultValue the default value of the property 35 | */ 36 | @SafeVarargs 37 | public ArrayProperty(@NotNull String path, @NotNull PropertyType type, T @NotNull ... defaultValue) { 38 | super(path, type, defaultValue); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/BaseProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.configme.properties.convertresult.PropertyValue; 5 | import ch.jalu.configme.resource.PropertyReader; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import org.jetbrains.annotations.Nullable; 9 | import java.util.Objects; 10 | 11 | /** 12 | * Base implementation of {@link Property}. All properties should extend from this class. 13 | *

14 | * This base implementation makes interacting with properties null safe by guaranteeing that the default value 15 | * and its {@link #determineValue determined value} can never be null. 16 | * 17 | * @param the property type 18 | */ 19 | public abstract class BaseProperty implements Property { 20 | 21 | private final String path; 22 | private final T defaultValue; 23 | 24 | /** 25 | * Constructor. 26 | * 27 | * @param path the path of the property 28 | * @param defaultValue the default value of the property 29 | */ 30 | public BaseProperty(@NotNull String path, @NotNull T defaultValue) { 31 | Objects.requireNonNull(path, "path"); 32 | Objects.requireNonNull(defaultValue, "defaultValue"); 33 | this.path = path; 34 | this.defaultValue = defaultValue; 35 | } 36 | 37 | @Override 38 | public @NotNull String getPath() { 39 | return path; 40 | } 41 | 42 | @Override 43 | public @NotNull T getDefaultValue() { 44 | return defaultValue; 45 | } 46 | 47 | @Override 48 | public @NotNull PropertyValue determineValue(@NotNull PropertyReader reader) { 49 | ConvertErrorRecorder errorRecorder = new ConvertErrorRecorder(); 50 | T value = getFromReader(reader, errorRecorder); 51 | if (isValidValue(value)) { 52 | return new PropertyValue<>(value, errorRecorder.isFullyValid()); 53 | } 54 | return PropertyValue.withValueRequiringRewrite(getDefaultValue()); 55 | } 56 | 57 | @Override 58 | public boolean isValidValue(@Nullable T value) { 59 | return value != null; 60 | } 61 | 62 | /** 63 | * Constructs the value of the property from the property reader. Returns null if no value is 64 | * available in the reader or if it cannot be used to construct a value for this property. 65 | * 66 | * @param reader the reader to read from 67 | * @param errorRecorder error recorder to register errors even if a valid value is returned 68 | * @return value based on the reader, or null if not applicable 69 | */ 70 | protected abstract @Nullable T getFromReader(@NotNull PropertyReader reader, 71 | @NotNull ConvertErrorRecorder errorRecorder); 72 | 73 | @Override 74 | public @NotNull String toString() { 75 | return "Property '" + path + "'"; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/BeanProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.beanmapper.DefaultMapper; 4 | import ch.jalu.configme.beanmapper.Mapper; 5 | import ch.jalu.configme.exception.ConfigMeException; 6 | import ch.jalu.configme.properties.types.BeanPropertyType; 7 | import ch.jalu.typeresolver.TypeInfo; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Property whose value is a bean class. 12 | * 13 | * @param the bean type 14 | */ 15 | public class BeanProperty extends TypeBasedProperty { 16 | 17 | public BeanProperty(@NotNull String path, @NotNull Class beanType, @NotNull T defaultValue) { 18 | this(path, beanType, defaultValue, DefaultMapper.getInstance()); 19 | } 20 | 21 | public BeanProperty(@NotNull String path, @NotNull Class beanType, @NotNull T defaultValue, 22 | @NotNull Mapper mapper) { 23 | super(path, BeanPropertyType.of(beanType, mapper), defaultValue); 24 | } 25 | 26 | public BeanProperty(@NotNull String path, @NotNull BeanPropertyType type, @NotNull T defaultValue) { 27 | super(path, type, defaultValue); 28 | } 29 | 30 | /** 31 | * Constructor. Allows to instantiate bean properties with generic types. Since it is hard to validate that 32 | * the default value is actually correct, it is recommended to extend this class with specific type parameters. 33 | * 34 | * @param path the path 35 | * @param beanType the bean type 36 | * @param defaultValue the default value 37 | * @param mapper the mapper to map with 38 | */ 39 | protected BeanProperty(@NotNull String path, @NotNull TypeInfo beanType, @NotNull T defaultValue, 40 | @NotNull Mapper mapper) { 41 | super(path, new BeanPropertyType<>(beanType, mapper), defaultValue); 42 | 43 | 44 | Class beanClass = beanType.toClass(); 45 | if (beanClass == null) { 46 | throw new IllegalArgumentException("The bean type '" + beanType + "' cannot be converted to Class. " 47 | + "Use a constructor with a custom BeanPropertyType."); 48 | } else if (!beanClass.isInstance(defaultValue)) { 49 | throw new ConfigMeException( 50 | "Default value for path '" + path + "' does not match bean type '" + beanType + "'"); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/BooleanProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.BooleanType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Boolean property. This extension exists for convenience. 8 | */ 9 | public class BooleanProperty extends TypeBasedProperty { 10 | 11 | public BooleanProperty(@NotNull String path, boolean defaultValue) { 12 | super(path, BooleanType.BOOLEAN, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/DoubleProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Double property. This extension exists for convenience. 8 | */ 9 | public class DoubleProperty extends TypeBasedProperty { 10 | 11 | public DoubleProperty(@NotNull String path, double defaultValue) { 12 | super(path, NumberType.DOUBLE, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/EnumProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.EnumPropertyType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Enum property. 8 | * 9 | * @param the enum type 10 | */ 11 | public class EnumProperty> extends TypeBasedProperty { 12 | 13 | public EnumProperty(@NotNull String path, @NotNull Class clazz, @NotNull E defaultValue) { 14 | super(path, EnumPropertyType.of(clazz), defaultValue); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/EnumSetProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.EnumSetPropertyType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Arrays; 7 | import java.util.EnumSet; 8 | import java.util.Set; 9 | 10 | /** 11 | * EnumSet property. 12 | * 13 | * @param the enum type 14 | */ 15 | public class EnumSetProperty> extends SetProperty { 16 | 17 | public EnumSetProperty(@NotNull String path, @NotNull Class enumClass, @NotNull EnumSet defaultValue) { 18 | super(new EnumSetPropertyType(enumClass), path, defaultValue); 19 | } 20 | 21 | public EnumSetProperty(@NotNull String path, @NotNull Class enumClass, @NotNull E @NotNull... defaultValue) { 22 | super(new EnumSetPropertyType(enumClass), path, newEnumSet(enumClass, defaultValue)); 23 | } 24 | 25 | private static > @NotNull Set newEnumSet(@NotNull Class enumClass, 26 | E @NotNull [] defaultValue) { 27 | EnumSet enumSet = EnumSet.noneOf(enumClass); 28 | enumSet.addAll(Arrays.asList(defaultValue)); 29 | return enumSet; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/FloatProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Float property. This extension exists for convenience. 8 | */ 9 | public class FloatProperty extends TypeBasedProperty { 10 | 11 | public FloatProperty(@NotNull String path, float defaultValue) { 12 | super(path, NumberType.FLOAT, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/InlineArrayProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.InlineArrayPropertyType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Array property which reads and stores its value as one String in which the elements 8 | * are separated by a delimiter. 9 | * 10 | * @param the array element type 11 | */ 12 | public class InlineArrayProperty extends TypeBasedProperty { 13 | 14 | /** 15 | * Constructor. 16 | * 17 | * @param path the path of the property 18 | * @param inlineArrayType the inline array property type 19 | * @param defaultValue the default value of the property 20 | */ 21 | public InlineArrayProperty(@NotNull String path, 22 | @NotNull InlineArrayPropertyType inlineArrayType, 23 | T @NotNull [] defaultValue) { 24 | super(path, inlineArrayType, defaultValue); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/IntegerProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Integer property. This extension exists for convenience. 8 | */ 9 | public class IntegerProperty extends TypeBasedProperty { 10 | 11 | public IntegerProperty(@NotNull String path, int defaultValue) { 12 | super(path, NumberType.INTEGER, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/LongProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Long property. This extension exists for convenience. 8 | */ 9 | public class LongProperty extends TypeBasedProperty { 10 | 11 | public LongProperty(@NotNull String path, long defaultValue) { 12 | super(path, NumberType.LONG, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/LowercaseStringSetProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.StringType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collection; 8 | import java.util.LinkedHashSet; 9 | import java.util.Locale; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * Property whose value is a String set all in lowercase. The default value is immutable. 16 | * The encounter order of the default value and the constructed values is preserved. 17 | */ 18 | public class LowercaseStringSetProperty extends SetProperty { 19 | 20 | /** 21 | * Constructor. 22 | * 23 | * @param path property path 24 | * @param defaultEntries entries in the Set that is the default value 25 | */ 26 | public LowercaseStringSetProperty(@NotNull String path, @NotNull String @NotNull ... defaultEntries) { 27 | super(path, StringType.STRING_LOWER_CASE, toLowercaseLinkedHashSet(Arrays.stream(defaultEntries))); 28 | } 29 | 30 | /** 31 | * Constructor. 32 | * 33 | * @param path property path 34 | * @param defaultEntries entries in the Set that is the default value 35 | */ 36 | public LowercaseStringSetProperty(@NotNull String path, @NotNull Collection defaultEntries) { 37 | super(path, StringType.STRING_LOWER_CASE, toLowercaseLinkedHashSet(defaultEntries.stream())); 38 | } 39 | 40 | protected static @NotNull Set toLowercaseLinkedHashSet(@NotNull Stream valuesStream) { 41 | return valuesStream 42 | .map(value -> value.toLowerCase(Locale.ROOT)) 43 | .collect(Collectors.toCollection(LinkedHashSet::new)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/OptionalProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * Property which may be empty. 12 | *

13 | * Wraps another property with an {@link Optional}: if a property is not present in the property resource, 14 | * {@link Optional#empty} is returned. 15 | * 16 | * @param the type of value 17 | */ 18 | public class OptionalProperty implements Property> { 19 | 20 | private final Property baseProperty; 21 | private final Optional defaultValue; 22 | 23 | public OptionalProperty(@NotNull Property baseProperty) { 24 | this.baseProperty = baseProperty; 25 | this.defaultValue = Optional.empty(); 26 | } 27 | 28 | public OptionalProperty(@NotNull Property baseProperty, @NotNull T defaultValue) { 29 | this.baseProperty = baseProperty; 30 | this.defaultValue = Optional.of(defaultValue); 31 | } 32 | 33 | @Override 34 | public @NotNull String getPath() { 35 | return baseProperty.getPath(); 36 | } 37 | 38 | @Override 39 | public @NotNull PropertyValue> determineValue(@NotNull PropertyReader reader) { 40 | PropertyValue basePropertyValue = baseProperty.determineValue(reader); 41 | Optional value = basePropertyValue.isValidInResource() 42 | ? Optional.ofNullable(basePropertyValue.getValue()) 43 | : Optional.empty(); 44 | 45 | // Propagate the false "valid" property if the reader has a value at the base property's path 46 | // and the base property says it's invalid -> triggers a rewrite to get rid of the invalid value. 47 | boolean isWrongInResource = !basePropertyValue.isValidInResource() && reader.contains(baseProperty.getPath()); 48 | return isWrongInResource 49 | ? PropertyValue.withValueRequiringRewrite(value) 50 | : PropertyValue.withValidValue(value); 51 | } 52 | 53 | @Override 54 | public @NotNull Optional getDefaultValue() { 55 | return defaultValue; 56 | } 57 | 58 | @Override 59 | public boolean isValidValue(@Nullable Optional value) { 60 | if (value == null) { 61 | return false; 62 | } 63 | return value.map(baseProperty::isValidValue).orElse(true); 64 | } 65 | 66 | @Override 67 | public @Nullable Object toExportValue(@NotNull Optional value) { 68 | return value.map(baseProperty::toExportValue).orElse(null); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/RegexProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.SettingsManager; 4 | import ch.jalu.configme.properties.types.RegexType; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * Property whose value is a regex pattern. 12 | */ 13 | public class RegexProperty extends TypeBasedProperty { 14 | 15 | /** 16 | * Constructor. 17 | * 18 | * @param path the path of the property 19 | * @param defaultValue the default value of the property 20 | */ 21 | public RegexProperty(@NotNull String path, @NotNull Pattern defaultValue) { 22 | super(path, RegexType.REGEX, defaultValue); 23 | } 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param path the path of the property 29 | * @param defaultRegexValue the default value of the property 30 | */ 31 | public RegexProperty(@NotNull String path, @NotNull String defaultRegexValue) { 32 | this(path, Pattern.compile(defaultRegexValue)); 33 | } 34 | 35 | /** 36 | * Constructor that allows to specify a custom regex type. 37 | * 38 | * @param path the path of the property 39 | * @param type the property type 40 | * @param defaultValue the default value of the property 41 | */ 42 | public RegexProperty(@NotNull String path, @NotNull RegexType type, @NotNull Pattern defaultValue) { 43 | super(path, type, defaultValue); 44 | } 45 | 46 | /** 47 | * Creates a new case-insensitive regex property: the patterns handled by this property are case-insensitive. 48 | * 49 | * @param path the path of the property 50 | * @param defaultRegexValue the default value of the property 51 | * @return new case-insensitive regex property 52 | */ 53 | public static @NotNull RegexProperty caseInsensitive(@NotNull String path, @NotNull String defaultRegexValue) { 54 | return new RegexProperty(path, RegexType.REGEX_CASE_INSENSITIVE, 55 | Pattern.compile(defaultRegexValue, Pattern.CASE_INSENSITIVE)); 56 | } 57 | 58 | /** 59 | * Convenience method to evaluate whether the pattern set for this property matches the provided {@code value}. 60 | * 61 | * @param value the value to check whether it conforms to the configured pattern 62 | * @param settingsManager settings manager with which the configured pattern is retrieved 63 | * @return true if the value matches the pattern, false otherwise 64 | */ 65 | public boolean matches(@NotNull String value, @NotNull SettingsManager settingsManager) { 66 | Matcher matcher = settingsManager.getProperty(this).matcher(value); 67 | return matcher.matches(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/ShortProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Short property. This extension exists for convenience. 8 | */ 9 | public class ShortProperty extends TypeBasedProperty { 10 | 11 | public ShortProperty(@NotNull String path, short defaultValue) { 12 | super(path, NumberType.SHORT, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/StringListProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.StringType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * String list property. The lists are immutable. 10 | */ 11 | public class StringListProperty extends ListProperty { 12 | 13 | public StringListProperty(@NotNull String path, String @NotNull ... defaultValue) { 14 | super(path, StringType.STRING, defaultValue); 15 | } 16 | 17 | public StringListProperty(@NotNull String path, @NotNull List defaultValue) { 18 | super(path, StringType.STRING, defaultValue); 19 | } 20 | 21 | @Override 22 | public @NotNull Object toExportValue(@NotNull List value) { 23 | return value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/StringProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.StringType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * String property. This extension exists for convenience. 8 | */ 9 | public class StringProperty extends TypeBasedProperty { 10 | 11 | public StringProperty(@NotNull String path, @NotNull String defaultValue) { 12 | super(path, StringType.STRING, defaultValue); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/StringSetProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.StringType; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * String set property. The default value is immutable. The encounter order of the default value and 10 | * the constructed values is preserved. 11 | */ 12 | public class StringSetProperty extends SetProperty { 13 | 14 | /** 15 | * Constructor. 16 | * 17 | * @param path the path of the property 18 | * @param defaultValue the values that make up the entries of the default set 19 | */ 20 | public StringSetProperty(@NotNull String path, @NotNull String @NotNull... defaultValue) { 21 | super(path, StringType.STRING, defaultValue); 22 | } 23 | 24 | /** 25 | * Constructor. 26 | * 27 | * @param path the path of the property 28 | * @param defaultValue the values that make up the entries of the default set 29 | */ 30 | public StringSetProperty(@NotNull String path, @NotNull Set defaultValue) { 31 | super(path, StringType.STRING, defaultValue); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/TypeBasedProperty.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.configme.properties.types.PropertyType; 5 | import ch.jalu.configme.resource.PropertyReader; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import org.jetbrains.annotations.Nullable; 9 | import java.util.Objects; 10 | 11 | /** 12 | * Property implementation which relies on a {@link PropertyType}. 13 | * 14 | * @param type of property value 15 | */ 16 | public class TypeBasedProperty extends BaseProperty { 17 | 18 | private final PropertyType type; 19 | 20 | /** 21 | * Constructor. 22 | * 23 | * @param path the path of the property 24 | * @param type the property type 25 | * @param defaultValue the default value of the property 26 | */ 27 | public TypeBasedProperty(@NotNull String path, @NotNull PropertyType type, @NotNull T defaultValue) { 28 | super(path, defaultValue); 29 | Objects.requireNonNull(type, "type"); 30 | this.type = type; 31 | } 32 | 33 | @Override 34 | protected @Nullable T getFromReader(@NotNull PropertyReader reader, @NotNull ConvertErrorRecorder errorRecorder) { 35 | return type.convert(reader.getObject(getPath()), errorRecorder); 36 | } 37 | 38 | @Override 39 | public @Nullable Object toExportValue(@NotNull T value) { 40 | return type.toExportValue(value); 41 | } 42 | 43 | /** 44 | * @return the property type this property makes use of 45 | */ 46 | public @NotNull PropertyType getType() { 47 | return type; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/builder/PropertyBuilderUtils.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.builder; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | /** 6 | * Utilities for property builders. 7 | */ 8 | final class PropertyBuilderUtils { 9 | 10 | /** 11 | * Method name to reference in an error message, for property builders that have an 12 | * array, collection or map as their value. 13 | */ 14 | static final String ADD_TO_DEFAULT_VALUE_METHOD = "addToDefaultValue"; 15 | 16 | private PropertyBuilderUtils() { 17 | } 18 | 19 | /** 20 | * Verifies that the given path is not null, throwing an exception if it is. 21 | * 22 | * @param path the path to check 23 | */ 24 | static void requireNonNullPath(@Nullable String path) { 25 | if (path == null) { 26 | throw new IllegalStateException("The path of the property must be defined"); 27 | } 28 | } 29 | 30 | /** 31 | * Throws an exception referring to the method {@code addToDefaultValue} if the provided parameter indicates that 32 | * the default value collection/map is not empty. 33 | * 34 | * @param isEmpty whether the default value (collection/map) is currently empty 35 | */ 36 | static void verifyDefaultValueIsEmpty(boolean isEmpty) { 37 | if (!isEmpty) { 38 | throw new IllegalStateException("Default values have already been defined! Use " 39 | + ADD_TO_DEFAULT_VALUE_METHOD + " to add entries individually"); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/convertresult/ConvertErrorRecorder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.convertresult; 2 | 3 | import ch.jalu.configme.resource.PropertyReader; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Records errors during the conversion of a property to its Java value. 8 | *

9 | * This object is passed around during conversion to determine whether an error has occurred during the conversion that 10 | * should trigger a rewrite. It is not necessary to register an error with this class if the return value of the 11 | * conversion implies that the representation in the resource is wrong altogether. 12 | * Instead, errors are typically registered with this recorder when an object can be created, but there is some 13 | * error in the representation that should be corrected (e.g. a value is missing but there is a sensible fallback). 14 | * 15 | * @see ch.jalu.configme.properties.BaseProperty#determineValue(PropertyReader) 16 | */ 17 | public class ConvertErrorRecorder { 18 | 19 | private boolean hasError; 20 | 21 | /** 22 | * Registers that some error occurred during the conversion of the value. See class javadoc: no need to register 23 | * an error if the return value of the conversion implies there is an issue (such as returning null). 24 | * 25 | * @param reason the reason (not used in this implementation but may be extended for debugging) 26 | */ 27 | public void setHasError(@NotNull String reason) { 28 | hasError = true; 29 | } 30 | 31 | /** 32 | * Returns whether the value that was returned from the property or property type was fully valid and 33 | * therefore doesn't need a rewrite. Even if a value is returned, this method may return {@code false} in case 34 | * a recoverable error was detected. This method may return {@code true} if the return value of the conversion is 35 | * null or otherwise indicates that there is no proper representation of it in the property resource. 36 | * 37 | * @return true if no error was registered, false otherwise (see class Javadoc for semantics) 38 | */ 39 | public boolean isFullyValid() { 40 | return !hasError; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/ArrayPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.internal.ConversionUtils; 4 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.Objects; 12 | import java.util.function.IntFunction; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * Property type for arrays: wraps another property type, which handles individual array elements, into an array type. 17 | *

18 | * This property type never produces arrays that have any {@code null} elements. If an entry cannot be converted by the 19 | * entry type (the property type that converts individual array elements), it is skipped in the result. 20 | * 21 | * @param the type of the array's elements 22 | */ 23 | public class ArrayPropertyType implements PropertyType { 24 | 25 | private final PropertyType entryType; 26 | private final IntFunction arrayProducer; 27 | 28 | /** 29 | * Constructor. 30 | *

31 | * Note that many property types provided by ConfigMe have a method {@code arrayType()}, 32 | * e.g. {@link NumberType#arrayType()}, to create an array equivalent of the base type. 33 | * 34 | * @param entryType the type of the array's elements 35 | * @param arrayProducer function to create an array of the right type with the provided size 36 | */ 37 | public ArrayPropertyType(@NotNull PropertyType entryType, @NotNull IntFunction arrayProducer) { 38 | Objects.requireNonNull(entryType, "entryType"); 39 | Objects.requireNonNull(arrayProducer, "arrayProducer"); 40 | this.entryType = entryType; 41 | this.arrayProducer = arrayProducer; 42 | } 43 | 44 | @Override 45 | public T @Nullable [] convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 46 | if (object instanceof Collection) { 47 | Collection coll = (Collection) object; 48 | return coll.stream() 49 | .map(elem -> ConversionUtils.convertOrLogError(elem, entryType, errorRecorder)) 50 | .filter(Objects::nonNull) 51 | .toArray(arrayProducer); 52 | } 53 | return null; 54 | } 55 | 56 | @Override 57 | public @NotNull List toExportValue(T @NotNull [] value) { 58 | return Arrays.stream(value) 59 | .map(entryType::toExportValue) 60 | .collect(Collectors.toList()); 61 | } 62 | 63 | public final @NotNull PropertyType getEntryType() { 64 | return entryType; 65 | } 66 | 67 | /** 68 | * @return function to create an array with the given capacity 69 | */ 70 | public final @NotNull IntFunction getArrayProducer() { 71 | return arrayProducer; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/BeanPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.beanmapper.DefaultMapper; 4 | import ch.jalu.configme.beanmapper.Mapper; 5 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 6 | import ch.jalu.typeresolver.TypeInfo; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * Property type that maps values to a specific bean class. 12 | * 13 | * @param the bean type 14 | */ 15 | public class BeanPropertyType implements PropertyType { 16 | 17 | private final TypeInfo beanType; 18 | private final Mapper mapper; 19 | 20 | public BeanPropertyType(@NotNull TypeInfo beanType, @NotNull Mapper mapper) { 21 | this.beanType = beanType; 22 | this.mapper = mapper; 23 | } 24 | 25 | public static @NotNull BeanPropertyType of(@NotNull Class type, @NotNull Mapper mapper) { 26 | return new BeanPropertyType<>(new TypeInfo(type), mapper); 27 | } 28 | 29 | public static @NotNull BeanPropertyType of(@NotNull Class type) { 30 | return of(type, DefaultMapper.getInstance()); 31 | } 32 | 33 | @Override 34 | @SuppressWarnings("unchecked") 35 | public B convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 36 | return (B) mapper.convertToBean(object, beanType, errorRecorder); 37 | } 38 | 39 | @Override 40 | public @Nullable Object toExportValue(@NotNull B value) { 41 | return mapper.toExportValue(value); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/BooleanType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.typeresolver.TypeInfo; 5 | import ch.jalu.typeresolver.primitives.PrimitiveType; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * Property type and mapper leaf type for boolean values. 11 | */ 12 | public class BooleanType extends PropertyAndLeafType { 13 | 14 | /** Instance of this class. Named {@code BOOLEAN} rather than {@code INSTANCE} so it can be statically imported. */ 15 | public static final BooleanType BOOLEAN = new BooleanType(); 16 | 17 | /** 18 | * Constructor. Use {@link BooleanType#BOOLEAN} for the standard behavior. 19 | */ 20 | protected BooleanType() { 21 | super(Boolean.class); 22 | } 23 | 24 | @Override 25 | public @Nullable Boolean convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 26 | if (object instanceof Boolean) { 27 | return (Boolean) object; 28 | } else if (object instanceof String) { 29 | return convertFromString((String) object); 30 | } 31 | return null; 32 | } 33 | 34 | @Override 35 | public @NotNull Boolean toExportValue(@NotNull Boolean value) { 36 | return value; 37 | } 38 | 39 | @Override 40 | public boolean canConvertToType(@NotNull TypeInfo typeInformation) { 41 | Class requiredClass = PrimitiveType.toReferenceType(typeInformation.toClass()); 42 | return requiredClass != null && requiredClass.isAssignableFrom(Boolean.class); 43 | } 44 | 45 | /** 46 | * Converts the String value to its boolean value, if applicable. 47 | * 48 | * @param value the value to convert 49 | * @return boolean value represented by the string, or null if not applicable 50 | */ 51 | protected @Nullable Boolean convertFromString(@NotNull String value) { 52 | // Note: Explicitly check for true/false because Boolean#parseBoolean returns false for 53 | // any value it doesn't recognize 54 | if ("true".equalsIgnoreCase(value)) { 55 | return true; 56 | } else if ("false".equalsIgnoreCase(value)) { 57 | return false; 58 | } 59 | return null; 60 | } 61 | 62 | /** 63 | * @return array property type whose elements are managed by {@code this} boolean type 64 | */ 65 | public @NotNull ArrayPropertyType arrayType() { 66 | return new ArrayPropertyType<>(this, Boolean[]::new); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/EnumPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.internal.ConversionUtils; 4 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 5 | import ch.jalu.typeresolver.EnumUtils; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * Property type for an enum type. 11 | * 12 | * @param the enum type 13 | */ 14 | public class EnumPropertyType> implements PropertyType { 15 | 16 | private final Class enumType; 17 | 18 | /** 19 | * Constructor. You can also create instances with {@link EnumPropertyType#of}. 20 | * 21 | * @param enumType the enum type this type should convert to 22 | */ 23 | public EnumPropertyType(@NotNull Class enumType) { 24 | this.enumType = enumType; 25 | } 26 | 27 | public static > @NotNull EnumPropertyType of(@NotNull Class type) { 28 | return new EnumPropertyType<>(type); 29 | } 30 | 31 | @Override 32 | @SuppressWarnings("unchecked") 33 | public @Nullable E convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 34 | if (object instanceof String) { 35 | return EnumUtils.tryValueOfCaseInsensitive(enumType, (String) object).orElse(null); 36 | } else if (enumType.isInstance(object)) { 37 | return (E) object; 38 | } 39 | return null; 40 | } 41 | 42 | @Override 43 | public @NotNull String toExportValue(@NotNull E value) { 44 | return value.name(); 45 | } 46 | 47 | public final @NotNull Class getEnumClass() { 48 | return enumType; 49 | } 50 | 51 | /** 52 | * @return array property type whose elements are managed by {@code this} enum type 53 | */ 54 | public @NotNull ArrayPropertyType arrayType() { 55 | return new ArrayPropertyType<>(this, size -> ConversionUtils.createArrayForReferenceType(enumType, size)); 56 | } 57 | 58 | /** 59 | * Creates an inline array property type with the given separator. 60 | * See {@link InlineArrayPropertyType} for more details. 61 | * 62 | * @param separator the sequence that acts as separator for multiple entries 63 | * @return inline array type with {@code this} type and the given separator 64 | */ 65 | public @NotNull InlineArrayPropertyType inlineArrayType(@NotNull String separator) { 66 | return new InlineArrayPropertyType<>(this, separator, true, 67 | size -> ConversionUtils.createArrayForReferenceType(enumType, size)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/EnumSetPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.EnumSet; 6 | import java.util.stream.Collector; 7 | import java.util.stream.Collectors; 8 | 9 | /** 10 | * Property type that manages an enum set. 11 | * 12 | * @param the enum type of the entries 13 | */ 14 | public class EnumSetPropertyType> extends CollectionPropertyType> { 15 | 16 | /** 17 | * Constructor. 18 | * 19 | * @param enumClass the enum class the entries should have 20 | */ 21 | public EnumSetPropertyType(@NotNull Class enumClass) { 22 | this(EnumPropertyType.of(enumClass)); 23 | } 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param entryType enum type of the entries 29 | */ 30 | public EnumSetPropertyType(@NotNull EnumPropertyType entryType) { 31 | super(entryType); 32 | } 33 | 34 | @Override 35 | public @NotNull EnumPropertyType getEntryType() { 36 | return (EnumPropertyType) super.getEntryType(); 37 | } 38 | 39 | public @NotNull Class getEnumClass() { 40 | return getEntryType().getEnumClass(); 41 | } 42 | 43 | @Override 44 | protected @NotNull Collector> resultCollector() { 45 | return Collectors.toCollection(() -> EnumSet.noneOf(getEnumClass())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/ListPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.stream.Collector; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * Property type for lists. 12 | * 13 | * @param the type of the elements in the list 14 | */ 15 | public class ListPropertyType extends CollectionPropertyType> { 16 | 17 | public ListPropertyType(@NotNull PropertyType entryType) { 18 | super(entryType); 19 | } 20 | 21 | @Override 22 | protected @NotNull Collector> resultCollector() { 23 | // Note: Collectors#toList creates an ArrayList, but the Javadoc makes no guarantees about what type of List 24 | // will actually be returned, so we'll explicitly use an ArrayList here. 25 | return Collectors.toCollection(ArrayList::new); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/PropertyAndLeafType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.beanmapper.leafvaluehandler.MapperLeafType; 4 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 5 | import ch.jalu.typeresolver.TypeInfo; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * Abstract class to implement {@link PropertyType} and {@link MapperLeafType} within the same class. 11 | *

12 | * Both implemented interfaces are independent of each other, but for many basic types, we want to make use of the same 13 | * conversion logic and behavior. This class facilitates such implementations. This class should not be used for 14 | * types where the conversion logic is not suitable as a property type and as a mapper leaf type—for 15 | * instance, {@link EnumPropertyType} is a property type implementation for properties where the enum class is 16 | * specifically defined, whereas {@link ch.jalu.configme.beanmapper.leafvaluehandler.EnumLeafType EnumLeafType} is the 17 | * equivalent mapper leaf type which generically handles all enums. 18 | * 19 | * @param the type this instance produces 20 | */ 21 | public abstract class PropertyAndLeafType implements PropertyType, MapperLeafType { 22 | 23 | private final Class clazz; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param clazz the class this type implementation produces 29 | */ 30 | public PropertyAndLeafType(@NotNull Class clazz) { 31 | this.clazz = clazz; 32 | } 33 | 34 | @Override 35 | public @Nullable Object convert(@Nullable Object value, @NotNull TypeInfo targetType, 36 | @NotNull ConvertErrorRecorder errorRecorder) { 37 | if (canConvertToType(targetType)) { 38 | return convert(value, errorRecorder); 39 | } 40 | return null; 41 | } 42 | 43 | @Override 44 | @SuppressWarnings("unchecked") 45 | public @Nullable Object toExportValueIfApplicable(@Nullable Object value) { 46 | if (clazz.isInstance(value)) { 47 | return toExportValue((T) value); 48 | } 49 | return null; 50 | } 51 | 52 | /** 53 | * Specifies whether this object can convert to the given type. Used by 54 | * {@link #convert(Object, TypeInfo, ConvertErrorRecorder)}. 55 | * 56 | * @param type the target type 57 | * @return true if this object can convert to the given type, false otherwise 58 | */ 59 | protected boolean canConvertToType(@NotNull TypeInfo type) { 60 | return type.isAssignableFrom(clazz); 61 | } 62 | 63 | /** 64 | * @return the class of the values this type converts to 65 | */ 66 | public final @NotNull Class getType() { 67 | return clazz; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/PropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | /** 9 | * Property type: provides methods for converting between property resource and a defined type 10 | * and allows to be used in generic structures such as an array property or map property. 11 | * 12 | * @param type of the values the property type handles 13 | */ 14 | public interface PropertyType { 15 | 16 | /** 17 | * Converts the given object (typically read from a property resource) to the given type, if possible. 18 | * Returns null otherwise. 19 | * 20 | * @param object the object to convert 21 | * @param errorRecorder error recorder to register errors even if a valid value is returned 22 | * @return the converted value, or null 23 | */ 24 | @Nullable T convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder); 25 | 26 | /** 27 | * Converts the given value to its export value. (Converts in the opposite way of {@link #convert}.) 28 | * 29 | * @param value the value to convert 30 | * @return the value to use in the property export 31 | */ 32 | @Nullable Object toExportValue(@NotNull T value); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/RegexType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.regex.Pattern; 8 | import java.util.regex.PatternSyntaxException; 9 | 10 | /** 11 | * Property type and mapper leaf type for regex. 12 | */ 13 | public class RegexType extends PropertyAndLeafType { 14 | 15 | /** Default regex type. */ 16 | public static final RegexType REGEX = new RegexType(); 17 | 18 | /** Case-insensitive regex type. */ 19 | public static final RegexType REGEX_CASE_INSENSITIVE = new RegexType() { 20 | @Override 21 | protected @NotNull Pattern compileToPattern(@NotNull String regex) { 22 | return Pattern.compile(regex, Pattern.CASE_INSENSITIVE); 23 | } 24 | }; 25 | 26 | /** 27 | * Constructor. Use {@link RegexType#REGEX} for the standard behavior. 28 | */ 29 | protected RegexType() { 30 | super(Pattern.class); 31 | } 32 | 33 | @Override 34 | public @Nullable Pattern convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 35 | if (object instanceof String) { 36 | String regex = (String) object; 37 | try { 38 | return compileToPattern(regex); 39 | } catch (PatternSyntaxException ignored) { 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | @Override 46 | public @Nullable Object toExportValue(@NotNull Pattern value) { 47 | return value.pattern(); 48 | } 49 | 50 | /** 51 | * Compiles the given string to a pattern object. 52 | * 53 | * @param regex the string to compile 54 | * @return the pattern object 55 | */ 56 | protected @NotNull Pattern compileToPattern(@NotNull String regex) { 57 | return Pattern.compile(regex); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/SetPropertyType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.LinkedHashSet; 6 | import java.util.Set; 7 | import java.util.stream.Collector; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * Property type for sets. The sets produced by this type are {@link LinkedHashSet}, 12 | * ensuring that insertion order is preserved. 13 | * 14 | * @param the type of the elements in the set 15 | */ 16 | public class SetPropertyType extends CollectionPropertyType> { 17 | 18 | public SetPropertyType(@NotNull PropertyType entryType) { 19 | super(entryType); 20 | } 21 | 22 | @Override 23 | protected @NotNull Collector> resultCollector() { 24 | return Collectors.toCollection(LinkedHashSet::new); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/properties/types/StringType.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.types; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Locale; 8 | 9 | /** 10 | * Property type and mapper leaf type for strings. 11 | */ 12 | public class StringType extends PropertyAndLeafType { 13 | 14 | /** Default string type. */ 15 | public static final StringType STRING = new StringType(); 16 | 17 | /** Lowercase string type. */ 18 | public static final StringType STRING_LOWER_CASE = new StringType() { 19 | @Override 20 | protected @NotNull String transformToString(@NotNull Object object) { 21 | return object.toString().toLowerCase(Locale.ROOT); 22 | } 23 | }; 24 | 25 | /** 26 | * Constructor. 27 | */ 28 | protected StringType() { 29 | super(String.class); 30 | } 31 | 32 | @Override 33 | public @Nullable String convert(@Nullable Object object, @NotNull ConvertErrorRecorder errorRecorder) { 34 | return object == null ? null : transformToString(object); 35 | } 36 | 37 | @Override 38 | public @NotNull String toExportValue(@NotNull String value) { 39 | return value; 40 | } 41 | 42 | /** 43 | * Converts the given object to a string. 44 | * 45 | * @param object the object to convert 46 | * @return the converted object 47 | */ 48 | protected @NotNull String transformToString(@NotNull Object object) { 49 | return object.toString(); 50 | } 51 | 52 | /** 53 | * @return array property type whose elements are managed by {@code this} String type 54 | */ 55 | public @NotNull ArrayPropertyType arrayType() { 56 | return new ArrayPropertyType<>(this, String[]::new); 57 | } 58 | 59 | /** 60 | * Creates an inline array property type with the given separator. 61 | * See {@link InlineArrayPropertyType} for more details. 62 | * 63 | * @param separator the sequence that acts as separator for multiple entries 64 | * @return inline array type with {@code this} type and the given separator 65 | */ 66 | public @NotNull InlineArrayPropertyType inlineArrayType(@NotNull String separator) { 67 | return new InlineArrayPropertyType<>(this, separator, false, String[]::new); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/resource/PropertyResource.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Represents a medium (typically a file on disk) from which property values should be built and allows to 8 | * write back to it. 9 | */ 10 | public interface PropertyResource { 11 | 12 | /** 13 | * Creates a reader to access the values in the medium (typically a file). 14 | *

15 | * The reader is discarded after its use and so is not required to refresh itself. 16 | * 17 | * @return reader providing values in the medium (e.g. file) 18 | */ 19 | @NotNull PropertyReader createReader(); 20 | 21 | /** 22 | * Exports the provided configuration data to the medium (typically a file). 23 | * 24 | * @param configurationData the configuration data to export 25 | */ 26 | void exportProperties(@NotNull ConfigurationData configurationData); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/resource/yaml/SnakeYamlNodeBuilder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource.yaml; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.yaml.snakeyaml.comments.CommentLine; 6 | import org.yaml.snakeyaml.nodes.Node; 7 | 8 | import java.util.stream.Stream; 9 | 10 | /** 11 | * Creates SnakeYAML nodes for values and comments. 12 | */ 13 | public interface SnakeYamlNodeBuilder { 14 | 15 | /** 16 | * Creates a SnakeYAML node representing the given value. 17 | * 18 | * @param value the value to create the node for (export value of a property) 19 | * @param path the path of the property whose value is exported 20 | * @param configurationData configuration data (for the retrieval of comments) 21 | * @param numberOfNewLines number of new lines before the property, to add as new lines to the node 22 | * @return SnakeYAML node of the appropriate type for the value, including comments 23 | */ 24 | @NotNull Node createYamlNode(@NotNull Object value, @NotNull String path, 25 | @NotNull ConfigurationData configurationData, int numberOfNewLines); 26 | 27 | /** 28 | * Creates a SnakeYAML string node for a key value (e.g. object property, or map key). 29 | * 30 | * @param key the key to wrap into a node 31 | * @return a node representing the key value 32 | */ 33 | @NotNull Node createKeyNode(@NotNull String key); 34 | 35 | /** 36 | * Creates SnakeYAML {@link CommentLine} objects to represent the given comment. If the comment is equal to the 37 | * new line character {@code \n}, one comment line representing a blank line is returned. Otherwise, a comment line 38 | * is created for each line (the text is split by {@code \n}). 39 | * 40 | * @param comment the comment to represent as CommentLine 41 | * @return stream with comment line objects representing the given comment 42 | */ 43 | @NotNull Stream createCommentLines(@NotNull String comment); 44 | 45 | /** 46 | * Transfers the comments from the value node to the key node. Logically, comments are associated with values, 47 | * but we do not want the comments to appear between the key and the value in the YAML output. Therefore, this 48 | * method is called before producing YAML as to move the comments from the value to the key node. 49 | * 50 | * @implNote Only considers {@link Node#getBlockComments() block comments} on the nodes because it's the only type 51 | * of comment that this builder sets. Any block comments on the key node are overwritten. 52 | * 53 | * @param valueNode the value node to remove the comments from 54 | * @param keyNode the key node to set the comments to 55 | */ 56 | void transferComments(@NotNull Node valueNode, @NotNull Node keyNode); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/resource/yaml/SnakeYamlNodeContainer.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource.yaml; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.yaml.snakeyaml.nodes.Node; 5 | 6 | import java.util.List; 7 | import java.util.function.Supplier; 8 | 9 | /** 10 | * Container that keeps SnakeYAML node objects in hierarchical order. Leaf values are SnakeYAML nodes, while parent 11 | * values are containers that can be converted to SnakeYAML nodes representing all enclosed values. 12 | */ 13 | public interface SnakeYamlNodeContainer { 14 | 15 | /** 16 | * Returns the existing container for the given name, or creates one and registers the comments as returned by the 17 | * supplier. An exception is thrown if a value (SnakeYAML node) was saved under the given name. 18 | * 19 | * @param name the path name to get 20 | * @param commentsSupplier supplier with comments to set if the container has to be created 21 | * @return container for the given path name 22 | */ 23 | @NotNull SnakeYamlNodeContainer getOrCreateChildContainer(@NotNull String name, 24 | @NotNull Supplier> commentsSupplier); 25 | 26 | /** 27 | * Returns the SnakeYAML node at the root path (empty string). Used as root of the YAML document when the 28 | * configuration only has one property at root path. Throws an exception if no value was stored for the root path. 29 | * 30 | * @return internal root node 31 | */ 32 | @NotNull Node getRootValueNode(); 33 | 34 | /** 35 | * Saves the given node under the given name (= path element). Throws an exception if a value is already associated 36 | * with the given name. 37 | * 38 | * @param name the name to save the value under 39 | * @param node the node to save 40 | */ 41 | void putNode(@NotNull String name, @NotNull Node node); 42 | 43 | /** 44 | * Converts this container and its sub-containers, recursively, to a SnakeYAML node that represents 45 | * all SnakeYAML nodes held by the containers. 46 | * 47 | * @param nodeBuilder node builder to create nodes with 48 | * @return this container's values as SnakeYAML node 49 | */ 50 | @NotNull Node convertToNode(@NotNull SnakeYamlNodeBuilder nodeBuilder); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.utils; 2 | 3 | import ch.jalu.configme.exception.ConfigMeException; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | 10 | /** 11 | * Class with file utilities. 12 | */ 13 | public final class FileUtils { 14 | 15 | private FileUtils() { 16 | } 17 | 18 | /** 19 | * Attempts to create the given Path (as file) if it doesn't exist. If creating the file 20 | * is unsuccessful, an exception is thrown. If the given path exists but is not a file, 21 | * an exception is thrown, too. 22 | * 23 | * @param file the file to create if it doesn't exist 24 | */ 25 | public static void createFileIfNotExists(@NotNull Path file) { 26 | if (Files.exists(file)) { 27 | if (!Files.isRegularFile(file)) { 28 | throw new ConfigMeException("Expected file but '" + file + "' is not a file"); 29 | } 30 | } else { 31 | Path parent = file.getParent(); 32 | if (!Files.exists(parent) || !Files.isDirectory(parent)) { 33 | try { 34 | Files.createDirectories(parent); 35 | } catch (IOException e) { 36 | throw new ConfigMeException("Failed to create parent folders for '" + file + "'", e); 37 | } 38 | } 39 | try { 40 | Files.createFile(file); 41 | } catch (IOException e) { 42 | throw new ConfigMeException("Failed to create file '" + file + "'", e); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/ch/jalu/configme/utils/MigrationUtils.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.utils; 2 | 3 | import ch.jalu.configme.configurationdata.ConfigurationData; 4 | import ch.jalu.configme.properties.Property; 5 | import ch.jalu.configme.properties.convertresult.PropertyValue; 6 | import ch.jalu.configme.resource.PropertyReader; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Migration utils. 11 | */ 12 | public final class MigrationUtils { 13 | 14 | private MigrationUtils() { 15 | } 16 | 17 | /** 18 | * Utility method: moves the value of an old property to a new property. This is only done if there is no value for 19 | * the new property in the configuration file and if there is one for the old property. Returns true if a value is 20 | * present at the old property path. 21 | * 22 | * @param oldProperty the old property (create a temporary {@link Property} object with the path) 23 | * @param newProperty the new property to move the value to 24 | * @param reader the property reader to read the configuration file from 25 | * @param configurationData configuration data to update a property's value 26 | * @param the type of the property 27 | * @return true if the old path exists in the configuration file, false otherwise 28 | */ 29 | public static boolean moveProperty(@NotNull Property oldProperty, 30 | @NotNull Property newProperty, 31 | @NotNull PropertyReader reader, 32 | @NotNull ConfigurationData configurationData) { 33 | if (reader.contains(oldProperty.getPath())) { 34 | if (!reader.contains(newProperty.getPath())) { 35 | PropertyValue value = oldProperty.determineValue(reader); 36 | configurationData.setValue(newProperty, value.getValue()); 37 | } 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/BeanDemoTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme; 2 | 3 | import ch.jalu.configme.demo.beans.BeanPropertiesDemo; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.equalTo; 12 | 13 | /** 14 | * Test for {@link BeanPropertiesDemo}. 15 | */ 16 | class BeanDemoTest { 17 | 18 | @Test 19 | void shouldOutputExpectedText() throws IOException { 20 | // given 21 | BeanPropertiesDemo beanDemo = new BeanPropertiesDemo(); 22 | 23 | try { 24 | // Perform the actual test 25 | shouldOutputExpectedText(beanDemo); 26 | } finally { 27 | // Cleanup - delete the temporary file 28 | Path file = beanDemo.getConfigFile(); 29 | if (file != null) { 30 | Files.delete(file); 31 | } 32 | } 33 | } 34 | 35 | private void shouldOutputExpectedText(BeanPropertiesDemo beanDemo) { 36 | // when 37 | String userInfo = beanDemo.generateUserInfo(); 38 | 39 | // then 40 | String expectedText = "Saved locations of Richie: restaurant (47.5, 8.7), hospital (47.1, 8.8901)" 41 | + "\nNicknames of Bob: Bobby, Bobby boy" 42 | + "\nCountry 'Sweden' has neighbors: Norway, Finland, Denmark"; 43 | assertThat(userInfo, equalTo(expectedText)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/ConfigDemoTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme; 2 | 3 | import ch.jalu.configme.demo.WelcomeWriter; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.equalTo; 12 | 13 | /** 14 | * Test for {@link WelcomeWriter}. 15 | */ 16 | class ConfigDemoTest { 17 | 18 | @Test 19 | void shouldGenerateExpectedHtml() throws IOException { 20 | // given 21 | WelcomeWriter writer = new WelcomeWriter(); 22 | 23 | try { 24 | // Perform the actual test 25 | shouldGenerateExpectedHtml(writer); 26 | } finally { 27 | // Cleanup - delete the temporary file 28 | Path file = writer.getConfigFile(); 29 | if (file != null) { 30 | Files.delete(file); 31 | } 32 | } 33 | } 34 | 35 | private void shouldGenerateExpectedHtml(WelcomeWriter writer) { 36 | // when 37 | String welcomeFile = writer.generateWelcomeFile(); 38 | 39 | // then 40 | String expectedText = "

Hello

" 41 | + System.getProperty("line.separator") 42 | + "Welcome!"; 43 | assertThat(welcomeFile, equalTo(expectedText)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/DefaultMapperTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | import static org.hamcrest.Matchers.sameInstance; 7 | 8 | /** 9 | * Test for {@link DefaultMapper}. 10 | */ 11 | class DefaultMapperTest { 12 | 13 | @Test 14 | void shouldReturnSameInstance() { 15 | // given 16 | Mapper givenInstance = DefaultMapper.getInstance(); 17 | 18 | // when 19 | Mapper instance = DefaultMapper.getInstance(); 20 | 21 | // then 22 | assertThat(instance, sameInstance(givenInstance)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/Command.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | /** 7 | * Command. 8 | */ 9 | public class Command { 10 | 11 | private String command; 12 | private List arguments = Collections.emptyList(); 13 | private ExecutionDetails execution; 14 | 15 | 16 | public String getCommand() { 17 | return command; 18 | } 19 | 20 | public void setCommand(String command) { 21 | this.command = command; 22 | } 23 | 24 | public List getArguments() { 25 | return arguments; 26 | } 27 | 28 | public void setArguments(List arguments) { 29 | this.arguments = arguments; 30 | } 31 | 32 | public ExecutionDetails getExecution() { 33 | return execution; 34 | } 35 | 36 | public void setExecution(ExecutionDetails execution) { 37 | this.execution = execution; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/CommandConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Command configuration. 7 | */ 8 | public class CommandConfig { 9 | 10 | private Map commands; 11 | private int duration; 12 | 13 | public Map getCommands() { 14 | return commands; 15 | } 16 | 17 | public void setCommands(Map commands) { 18 | this.commands = commands; 19 | } 20 | 21 | public int getDuration() { 22 | return duration; 23 | } 24 | 25 | public void setDuration(int duration) { 26 | this.duration = duration; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/ExecutionDetails.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command; 2 | 3 | import ch.jalu.configme.Comment; 4 | 5 | import java.util.Arrays; 6 | import java.util.LinkedHashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * Command execution details. 11 | */ 12 | public class ExecutionDetails { 13 | 14 | private Executor executor; 15 | private boolean optional; 16 | @Comment(value = "The higher the number, the more important", repeat = true) 17 | private Double importance; 18 | private Set privileges; 19 | 20 | public ExecutionDetails() { 21 | } 22 | 23 | public ExecutionDetails(Executor executor, double importance, boolean isOptional, String... privileges) { 24 | this.executor = executor; 25 | this.optional = isOptional; 26 | this.importance = importance; 27 | this.privileges = new LinkedHashSet<>(Arrays.asList(privileges)); 28 | } 29 | 30 | public Executor getExecutor() { 31 | return executor; 32 | } 33 | 34 | public void setExecutor(Executor executor) { 35 | this.executor = executor; 36 | } 37 | 38 | public boolean isOptional() { 39 | return optional; 40 | } 41 | 42 | public void setOptional(boolean optional) { 43 | this.optional = optional; 44 | } 45 | 46 | public Double getImportance() { 47 | return importance; 48 | } 49 | 50 | public void setImportance(Double importance) { 51 | this.importance = importance; 52 | } 53 | 54 | public Set getPrivileges() { 55 | return privileges; 56 | } 57 | 58 | public void setPrivileges(Set privileges) { 59 | this.privileges = privileges; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/Executor.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command; 2 | 3 | /** 4 | * Command executor. 5 | */ 6 | public enum Executor { 7 | 8 | USER, CONSOLE 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/optionalproperties/ComplexCommand.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command.optionalproperties; 2 | 3 | import ch.jalu.configme.beanmapper.command.Command; 4 | import ch.jalu.configme.samples.TestEnum; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * Extension of sample {@link Command} class. 10 | */ 11 | public class ComplexCommand extends Command { 12 | 13 | private Optional nameStartsWith; 14 | private Optional nameHasLength; 15 | private Optional testEnumProperty; 16 | private Optional doubleOptional; 17 | 18 | public Optional getNameStartsWith() { 19 | return nameStartsWith; 20 | } 21 | 22 | public void setNameStartsWith(Optional nameStartsWith) { 23 | this.nameStartsWith = nameStartsWith; 24 | } 25 | 26 | public Optional getNameHasLength() { 27 | return nameHasLength; 28 | } 29 | 30 | public void setNameHasLength(Optional nameHasLength) { 31 | this.nameHasLength = nameHasLength; 32 | } 33 | 34 | public Optional getTestEnumProperty() { 35 | return testEnumProperty; 36 | } 37 | 38 | public void setTestEnumProperty(Optional testEnumProperty) { 39 | this.testEnumProperty = testEnumProperty; 40 | } 41 | 42 | public Optional getDoubleOptional() { 43 | return doubleOptional; 44 | } 45 | 46 | public void setDoubleOptional(Optional doubleOptional) { 47 | this.doubleOptional = doubleOptional; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/optionalproperties/ComplexCommandConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command.optionalproperties; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Like {@link ch.jalu.configme.beanmapper.command.CommandConfig} but for {@link ComplexCommand}. 7 | */ 8 | public class ComplexCommandConfig { 9 | 10 | private Map commands; 11 | private int duration; 12 | 13 | public Map getCommands() { 14 | return commands; 15 | } 16 | 17 | public void setCommands(Map commands) { 18 | this.commands = commands; 19 | } 20 | 21 | public int getDuration() { 22 | return duration; 23 | } 24 | 25 | public void setDuration(int duration) { 26 | this.duration = duration; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/command/optionalproperties/ComplexOptionalTypeConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.command.optionalproperties; 2 | 3 | import java.util.Map; 4 | import java.util.Optional; 5 | 6 | /** 7 | * Sample class with complex type inside an Optional. 8 | */ 9 | public class ComplexOptionalTypeConfig { 10 | 11 | private Optional> commandconfig; 12 | 13 | public Optional> getCommandconfig() { 14 | return commandconfig; 15 | } 16 | 17 | public void setCommandconfig(Optional> commandconfig) { 18 | this.commandconfig = commandconfig; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/migratingbeanmapper/BeanExtensionSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.migratingbeanmapper; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.BeanProperty; 5 | import ch.jalu.configme.properties.Property; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class BeanExtensionSettingsHolder implements SettingsHolder { 11 | 12 | public static final Property CHAT_COMPONENT = new BeanProperty<>( 13 | "message-key", CollectionChatComponent.class, new CollectionChatComponent(), new SingleValueToCollectionMapper()); 14 | 15 | 16 | public static class CollectionChatComponent { 17 | 18 | private List color; 19 | private String text; 20 | private List extra = new ArrayList<>(); 21 | 22 | public List getColor() { 23 | return color; 24 | } 25 | 26 | public void setColor(List color) { 27 | this.color = color; 28 | } 29 | 30 | public String getText() { 31 | return text; 32 | } 33 | 34 | public void setText(String text) { 35 | this.text = text; 36 | } 37 | 38 | public List getExtra() { 39 | return extra; 40 | } 41 | 42 | public void setExtra(List extra) { 43 | this.extra = extra; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/migratingbeanmapper/BeanExtensionTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.migratingbeanmapper; 2 | 3 | import ch.jalu.configme.SettingsManager; 4 | import ch.jalu.configme.SettingsManagerBuilder; 5 | import ch.jalu.configme.TestUtils; 6 | import ch.jalu.configme.beanmapper.migratingbeanmapper.BeanExtensionSettingsHolder.CollectionChatComponent; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.contains; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.hasSize; 13 | 14 | /** 15 | * Test for {@link SingleValueToCollectionMapper}. 16 | */ 17 | public class BeanExtensionTest { 18 | 19 | private static final String CONFIG_FILE = "/beanmapper/nested_chat_component.yml"; 20 | 21 | @Test 22 | public void shouldLoadFileAndConvertSingleValuesToCollection() { 23 | // given 24 | SettingsManager settingsManager = SettingsManagerBuilder 25 | .withYamlFile(TestUtils.getJarPath(CONFIG_FILE)) 26 | .configurationData(BeanExtensionSettingsHolder.class) 27 | .create(); 28 | 29 | // when 30 | CollectionChatComponent result = settingsManager.getProperty(BeanExtensionSettingsHolder.CHAT_COMPONENT); 31 | 32 | // then 33 | assertThat(result.getColor(), contains("blue")); 34 | assertThat(result.getExtra(), hasSize(2)); 35 | assertThat(result.getExtra().get(0).getColor(), contains("green")); 36 | assertThat(result.getExtra().get(0).getText(), equalTo("inner1")); 37 | assertThat(result.getExtra().get(1).getColor(), contains("blue")); 38 | assertThat(result.getExtra().get(1).getText(), equalTo("inner2")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/migratingbeanmapper/SingleValueToCollectionMapper.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.migratingbeanmapper; 2 | 3 | import ch.jalu.configme.beanmapper.MapperImpl; 4 | import ch.jalu.configme.beanmapper.context.MappingContext; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | 11 | /** 12 | * Extension of the bean mapper representing a simple migration where a property is changed from 13 | * a single value to a collection. This mapper wraps a single value into a collection whenever a 14 | * collection should be constructed. Example for issue #117. 15 | */ 16 | public class SingleValueToCollectionMapper extends MapperImpl { 17 | 18 | @Override 19 | protected @Nullable Collection convertToCollection(@NotNull MappingContext context, @Nullable Object value) { 20 | if (!(value instanceof Iterable)) { 21 | Collection coll = super.convertToCollection(context, Collections.singleton(value)); 22 | // Register error to trigger a rewrite with the proper structure 23 | context.registerError("Found single value where a collection is expected"); 24 | return isCollectionWithOneElement(coll) ? coll : null; 25 | } 26 | return super.convertToCollection(context, value); 27 | } 28 | 29 | private static boolean isCollectionWithOneElement(Collection coll) { 30 | return coll != null && coll.size() == 1; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/typeissues/GenericCollection.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.typeissues; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Class with collection using generics. 7 | */ 8 | public class GenericCollection { 9 | 10 | private String name = ""; 11 | private List collection; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public List getCollection() { 22 | return collection; 23 | } 24 | 25 | public void setCollection(List collection) { 26 | this.collection = collection; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/typeissues/MapWithNonStringKeys.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.typeissues; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Map with a key type other than String. 7 | */ 8 | public class MapWithNonStringKeys { 9 | 10 | private String name = ""; 11 | private Map map; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public Map getMap() { 22 | return map; 23 | } 24 | 25 | public void setMap(Map map) { 26 | this.map = map; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/typeissues/UnsupportedCollection.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.typeissues; 2 | 3 | import java.util.Deque; 4 | 5 | /** 6 | * Class with unsupported collection type. 7 | */ 8 | public class UnsupportedCollection { 9 | 10 | private String name = ""; 11 | private Deque collection; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public Deque getCollection() { 22 | return collection; 23 | } 24 | 25 | public void setCollection(Deque collection) { 26 | this.collection = collection; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/typeissues/UntypedCollection.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.typeissues; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Class with untyped collection. 7 | */ 8 | public class UntypedCollection { 9 | 10 | private String name; 11 | private List collection; 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | public List getCollection() { 22 | return collection; 23 | } 24 | 25 | public void setCollection(List collection) { 26 | this.collection = collection; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/typeissues/UntypedMap.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.typeissues; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Class with untyped map. 7 | */ 8 | public class UntypedMap { 9 | 10 | private String name = ""; 11 | private Map map; 12 | 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | public Map getMap() { 23 | return map; 24 | } 25 | 26 | public void setMap(Map map) { 27 | this.map = map; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/worldgroup/GameMode.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.worldgroup; 2 | 3 | /** 4 | * Gamemode enum. 5 | */ 6 | public enum GameMode { 7 | 8 | /** Creative. */ 9 | CREATIVE, 10 | 11 | /** Survival. */ 12 | SURVIVAL 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/worldgroup/Group.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.worldgroup; 2 | 3 | import ch.jalu.configme.beanmapper.ExportName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * World group. 9 | */ 10 | public class Group { 11 | 12 | private List worlds; 13 | @ExportName("default-gamemode") 14 | private GameMode defaultGamemode; 15 | 16 | public void setWorlds(List worlds) { 17 | this.worlds = worlds; 18 | } 19 | 20 | public List getWorlds() { 21 | return worlds; 22 | } 23 | 24 | public void setDefaultGamemode(GameMode defaultGamemode) { 25 | this.defaultGamemode = defaultGamemode; 26 | } 27 | 28 | public GameMode getDefaultGamemode() { 29 | return defaultGamemode; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/beanmapper/worldgroup/WorldGroupConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.beanmapper.worldgroup; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Main class for the world groups configuration. 7 | */ 8 | public class WorldGroupConfig { 9 | 10 | private Map groups; 11 | 12 | public Map getGroups() { 13 | return groups; 14 | } 15 | 16 | public void setGroups(Map groups) { 17 | this.groups = groups; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/PropertyValueTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | import static org.hamcrest.Matchers.equalTo; 8 | 9 | /** 10 | * Test for {@link PropertyValue}. 11 | */ 12 | class PropertyValueTest { 13 | 14 | @Test 15 | void shouldCreateValidInstance() { 16 | // given / when 17 | PropertyValue value = PropertyValue.withValidValue("test"); 18 | 19 | // then 20 | assertThat(value.getValue(), equalTo("test")); 21 | assertThat(value.isValidInResource(), equalTo(true)); 22 | } 23 | 24 | @Test 25 | void shouldCreateInvalidInstance() { 26 | // given / when 27 | PropertyValue value = PropertyValue.withValueRequiringRewrite(33); 28 | 29 | // then 30 | assertThat(value.getValue(), equalTo(33)); 31 | assertThat(value.isValidInResource(), equalTo(false)); 32 | } 33 | 34 | @Test 35 | void shouldIncludeValuesInToString() { 36 | // given 37 | PropertyValue value = PropertyValue.withValidValue(-3.254); 38 | 39 | // when 40 | String stringRepresentation = value.toString(); 41 | 42 | // then 43 | assertThat(stringRepresentation, equalTo("PropertyValue[valid=true, value='-3.254']")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/samples/AdditionalTestConfiguration.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata.samples; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 6 | import ch.jalu.configme.properties.Property; 7 | 8 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 9 | 10 | /** 11 | * Sample properties class with some additional properties. 12 | */ 13 | public final class AdditionalTestConfiguration implements SettingsHolder { 14 | 15 | @Comment("Seconds to sleep") 16 | public static final Property SLEEP = 17 | newProperty("additional.sleep", 10); 18 | 19 | @Comment("Additional name") 20 | public static final Property NAME = 21 | newProperty("additional.name", "Supplement"); 22 | 23 | @Comment("Show additional things") 24 | public static final Property SHOW_THINGS = 25 | newProperty("additional.enable", false); 26 | 27 | 28 | // Some additional fields that are either invalid properties or irrelevant 29 | private Property privateProperty = newProperty("test", "toast"); 30 | public static final boolean BOOL = true; 31 | public final Property nonStaticProperty = newProperty("something", 123); 32 | 33 | private AdditionalTestConfiguration() { 34 | } 35 | 36 | @Override 37 | public void registerComments(CommentsConfiguration conf) { 38 | conf.setComment("additional", "Section comment for 'additional'"); 39 | conf.setComment("bogus", "This section does not exist anywhere"); 40 | conf.setComment("other.section"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/samples/IllegalSettingsHolderConstructorClasses.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata.samples; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 5 | 6 | /** 7 | * Contains SettingsHolder classes with wrong constructors. 8 | */ 9 | public final class IllegalSettingsHolderConstructorClasses { 10 | 11 | private IllegalSettingsHolderConstructorClasses() { 12 | } 13 | 14 | /** 15 | * Class doesn't have a no-args constructor. 16 | */ 17 | public final static class MissingNoArgsConstructor implements SettingsHolder { 18 | 19 | MissingNoArgsConstructor(String str) { 20 | } 21 | } 22 | 23 | /** 24 | * Constructor throws exception. 25 | */ 26 | public final static class ThrowingConstructor implements SettingsHolder { 27 | ThrowingConstructor() { 28 | throw new IllegalStateException("Exception for testing"); 29 | } 30 | } 31 | 32 | /** 33 | * Class is abstract. 34 | */ 35 | public static abstract class AbstractClass implements SettingsHolder { 36 | AbstractClass() { 37 | } 38 | } 39 | 40 | /** 41 | * Class is an interface. 42 | */ 43 | public interface InterfaceSettingsHolder extends SettingsHolder { 44 | @Override 45 | default void registerComments(CommentsConfiguration conf) { 46 | conf.setComment("path", "comment"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/samples/inheritance/ChildInheritanceSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata.samples.inheritance; 2 | 3 | import ch.jalu.configme.properties.Property; 4 | 5 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 6 | 7 | /** 8 | * Sample settings holder class with inheritance (don't do this). 9 | */ 10 | public class ChildInheritanceSettingsHolder extends MiddleInheritanceSettingsHolder { 11 | 12 | public static final Property CHILD_DOUBLE = newProperty("child.double", 5.3); 13 | 14 | public static final Property SAMPLE_SUBTITLE = newProperty("sample.subtitle", ""); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/samples/inheritance/MiddleInheritanceSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata.samples.inheritance; 2 | 3 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 4 | import ch.jalu.configme.properties.Property; 5 | 6 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 7 | 8 | public class MiddleInheritanceSettingsHolder extends TopInheritanceSettingsHolder { 9 | 10 | public static final Property MIDDLE_VERSION = newProperty("middle.version", 5); 11 | 12 | public static final Property SAMPLE_NAME = newProperty("sample.name", "Sample"); 13 | 14 | @Override 15 | public void registerComments(CommentsConfiguration conf) { 16 | conf.setComment("middle", "Comes from the holder in the middle"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/configurationdata/samples/inheritance/TopInheritanceSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.configurationdata.samples.inheritance; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.Property; 5 | 6 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 7 | 8 | public class TopInheritanceSettingsHolder implements SettingsHolder { 9 | 10 | public static final Property STRING_FROM_TOP = newProperty("top.string", "aaa"); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/Color.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo; 2 | 3 | /** 4 | * Colors. 5 | */ 6 | public enum Color { 7 | 8 | GREEN("#0f0"), 9 | 10 | BLUE("#00f"), 11 | 12 | RED("#f00"), 13 | 14 | ORANGE("#f50"); 15 | 16 | public final String hexCode; 17 | 18 | Color(String hexCode) { 19 | this.hexCode = hexCode; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/README.md: -------------------------------------------------------------------------------- 1 | ## ConfigMe demo 2 | 3 | This folder contains a small demonstration showing how ConfigMe can be used. 4 | You can find the config.yml file [here](https://github.com/AuthMe/ConfigMe/blob/master/src/test/resources/demo/config.yml). 5 | 6 | TitleConfig contains some `Property` fields which represent the properties in the config.yml file. 7 | These sample properties are then used in `WelcomeWriter` in order to generate a short text with 8 | configurable elements. 9 | 10 | Feel free to modify the config.yml file to see how this will change in behavior. 11 | The PlainMigrationService that is passed to the SettingsManager checks that all known properties 12 | are present in the config.yml file; if not, it will save the file, which triggers all absent 13 | properties to be saved with their default value. 14 | 15 | You can also add a new Property field to the `TitleConfig` and see how you can immediately use it 16 | in your application, even without worrying about `null` values. Users with an old config.yml file 17 | will automatically be migrated and will find the new property with its default value next time they 18 | start the application. 19 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/TitleConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.Property; 5 | 6 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 7 | 8 | /** 9 | * Sample file with property fields. You can have multiple classes with property fields 10 | * to separate the properties thematically as your configuration grows. 11 | */ 12 | public class TitleConfig implements SettingsHolder { 13 | 14 | public static final Property TITLE_TEXT = 15 | newProperty("title.text", "Test"); 16 | 17 | public static final Property TITLE_SIZE = 18 | newProperty("title.size", 12); 19 | 20 | public static final Property SUBTITLE_TEXT = 21 | newProperty("subtitle.text", "hello world"); 22 | 23 | public static final Property SUBTITLE_SIZE = 24 | newProperty("subtitle.size", 10); 25 | 26 | public static final Property SUBTITLE_COLOR = 27 | newProperty(Color.class, "subtitle.color", Color.ORANGE); 28 | 29 | private TitleConfig() { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/WelcomeWriter.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo; 2 | 3 | import ch.jalu.configme.SettingsManager; 4 | import ch.jalu.configme.SettingsManagerBuilder; 5 | import ch.jalu.configme.TestUtils; 6 | 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | 11 | import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; 12 | 13 | /** 14 | * Demo application that creates a "Welcome" HTML file based on some configurable properties. 15 | */ 16 | public class WelcomeWriter { 17 | 18 | private Path configFile; 19 | 20 | public static void main(String... args) { 21 | System.out.println("Generating HTML as per the config.yml file"); 22 | System.out.println("------------------"); 23 | WelcomeWriter writer = new WelcomeWriter(); 24 | System.out.println(writer.generateWelcomeFile()); 25 | System.out.println("------------------"); 26 | System.out.println("Copied config file to '" + writer.configFile + "'"); 27 | } 28 | 29 | /** 30 | * Generates the welcome file based on the settings. 31 | * 32 | * @return generated HTML welcome message 33 | */ 34 | public String generateWelcomeFile() { 35 | SettingsManager settings = initSettings(); 36 | String welcomeFilePattern = "" 37 | + "

%s

" 38 | + "%n%s"; 39 | 40 | Color subtitleColor = settings.getProperty(TitleConfig.SUBTITLE_COLOR); 41 | return String.format(welcomeFilePattern, settings.getProperty(TitleConfig.TITLE_SIZE), 42 | settings.getProperty(TitleConfig.TITLE_TEXT), subtitleColor.hexCode, 43 | settings.getProperty(TitleConfig.SUBTITLE_SIZE), settings.getProperty(TitleConfig.SUBTITLE_TEXT)); 44 | } 45 | 46 | /** 47 | * @return the temporary config file 48 | */ 49 | public Path getConfigFile() { 50 | return configFile; 51 | } 52 | 53 | /** 54 | * Initializes the settings manager. 55 | * 56 | * @return the settings manager 57 | */ 58 | private SettingsManager initSettings() { 59 | // Copy the demo/config.yml instead of using it directly so it doesn't get overridden 60 | configFile = copyFileFromJar("/demo/config.yml"); 61 | return SettingsManagerBuilder.withYamlFile(configFile).configurationData(TitleConfig.class).create(); 62 | } 63 | 64 | /** 65 | * Copies a file from the codebase's resources to a temporary file. 66 | * 67 | * @param path the path to copy 68 | * @return the copied file 69 | */ 70 | private static Path copyFileFromJar(String path) { 71 | try { 72 | Path file = Files.createTempFile("configme-", "-democonfig.yml"); 73 | Files.copy(TestUtils.class.getResourceAsStream(path), file, REPLACE_EXISTING); 74 | return file; 75 | } catch (IOException e) { 76 | throw new IllegalStateException(e); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/BeanPropertiesDemo.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | import ch.jalu.configme.SettingsManager; 4 | import ch.jalu.configme.SettingsManagerBuilder; 5 | import ch.jalu.configme.TestUtils; 6 | 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.util.stream.Collectors; 11 | 12 | import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; 13 | 14 | /** 15 | * Runnable demo showing how bean properties can be used. 16 | */ 17 | public class BeanPropertiesDemo { 18 | 19 | private Path configFile; 20 | 21 | public BeanPropertiesDemo() { 22 | configFile = copyFileFromJar("/demo/bean_demo_config.yml"); 23 | } 24 | 25 | public static void main(String... args) { 26 | BeanPropertiesDemo demo = new BeanPropertiesDemo(); 27 | 28 | System.out.println(demo.generateUserInfo()); 29 | System.out.println("Copied config file to '" + demo.configFile + "'"); 30 | } 31 | 32 | public String generateUserInfo() { 33 | SettingsManager settingsManager = SettingsManagerBuilder.withYamlFile(configFile) 34 | .configurationData(DemoSettings.class).create(); 35 | UserBase userBase = settingsManager.getProperty(DemoSettings.USER_BASE); 36 | 37 | User richie = userBase.getRichie(); 38 | String savedLocationInfo = richie.getSavedLocations().entrySet().stream() 39 | .map(entry -> entry.getKey() + " " + entry.getValue()) 40 | .collect(Collectors.joining(", ")); 41 | String info = "Saved locations of Richie: " + savedLocationInfo; 42 | 43 | info += "\nNicknames of Bob: " + String.join(", ", userBase.getBobby().getNicknames()); 44 | 45 | Country country = settingsManager.getProperty(DemoSettings.COUNTRY); 46 | info += "\nCountry '" + country.getName() + "' has neighbors: " + String.join(", ", country.getNeighbors()); 47 | return info; 48 | } 49 | 50 | /** 51 | * @return the config file 52 | */ 53 | public Path getConfigFile() { 54 | return configFile; 55 | } 56 | 57 | /** 58 | * Copies a file from the codebase's resources to a temporary file. 59 | * 60 | * @param path the path to copy 61 | * @return the copied file 62 | */ 63 | private static Path copyFileFromJar(String path) { 64 | try { 65 | Path tempFile = Files.createTempFile("configme-", "-beandemoconfig.yml"); 66 | Files.copy(TestUtils.class.getResourceAsStream(path), tempFile, REPLACE_EXISTING); 67 | return tempFile; 68 | } catch (IOException e) { 69 | throw new IllegalStateException(e); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/CoordinateSystem.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | /** 4 | * Coordinate systems. 5 | */ 6 | public enum CoordinateSystem { 7 | 8 | /** International Terrestrial Reference System. */ 9 | ITRS, 10 | 11 | /** North American Datum. */ 12 | NAD, 13 | 14 | /** European Datum 1950. */ 15 | ED50 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/Country.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | import java.beans.Transient; 4 | import java.util.List; 5 | 6 | /** 7 | * Country bean. 8 | */ 9 | public class Country { 10 | 11 | private String name; 12 | private int population; 13 | private List neighbors; 14 | private transient boolean isTemporary; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public void setName(String name) { 21 | this.name = name; 22 | } 23 | 24 | public int getPopulation() { 25 | return population; 26 | } 27 | 28 | public void setPopulation(int population) { 29 | this.population = population; 30 | } 31 | 32 | public List getNeighbors() { 33 | return neighbors; 34 | } 35 | 36 | public void setNeighbors(List neighbors) { 37 | this.neighbors = neighbors; 38 | } 39 | 40 | @Transient 41 | public boolean isTemporary() { 42 | return isTemporary; 43 | } 44 | 45 | public void setTemporary(boolean temporary) { 46 | isTemporary = temporary; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/DemoSettings.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.Property; 5 | 6 | import java.util.ArrayList; 7 | 8 | import static ch.jalu.configme.properties.PropertyInitializer.newBeanProperty; 9 | 10 | /** 11 | * Holds the settings we want to use. 12 | */ 13 | public final class DemoSettings implements SettingsHolder { 14 | 15 | public static final Property USER_BASE = 16 | newBeanProperty(UserBase.class, "userdata", initDefaultUserBase()); 17 | 18 | public static final Property COUNTRY = 19 | newBeanProperty(Country.class, "country", initDefaultCountry()); 20 | 21 | private DemoSettings() { 22 | } 23 | 24 | /** 25 | * @return user base with default values 26 | */ 27 | private static UserBase initDefaultUserBase() { 28 | User user = new User(); 29 | user.setName(""); 30 | user.setHomeLocation(new Location()); 31 | 32 | UserBase userBase = new UserBase(); 33 | userBase.setBobby(user); 34 | userBase.setRichie(user); 35 | userBase.setLionel(user); 36 | userBase.setVersion(0); 37 | return userBase; 38 | } 39 | 40 | /** 41 | * @return country object with default values 42 | */ 43 | private static Country initDefaultCountry() { 44 | Country country = new Country(); 45 | country.setName(""); 46 | country.setNeighbors(new ArrayList<>()); 47 | return country; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/Location.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | /** 4 | * Location bean. 5 | */ 6 | public class Location { 7 | 8 | private float longitude; 9 | private float latitude; 10 | private CoordinateSystem coordinateType = CoordinateSystem.ITRS; 11 | 12 | public float getLongitude() { 13 | return longitude; 14 | } 15 | 16 | public void setLongitude(float longitude) { 17 | this.longitude = longitude; 18 | } 19 | 20 | public float getLatitude() { 21 | return latitude; 22 | } 23 | 24 | public void setLatitude(float latitude) { 25 | this.latitude = latitude; 26 | } 27 | 28 | public CoordinateSystem getCoordinateType() { 29 | return coordinateType; 30 | } 31 | 32 | public void setCoordinateType(CoordinateSystem coordinateType) { 33 | this.coordinateType = coordinateType; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "(" + longitude + ", " + latitude + ")"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/README.md: -------------------------------------------------------------------------------- 1 | ## Demo with beans 2 | 3 | This is a demo showing how you can use custom JavaBeans with ConfigMe. The classes `Location`, 4 | `User`, and `UserBase` are JavaBeans. ConfigMe can scan these classes to determine the properties 5 | they have and will then use the config.yml file to create new objects with the data inside 6 | config.yml. `BeanPropertiesDemo` creates a settings manager and uses it to get the 7 | `DemoSettings.USER_BASE` setting. 8 | 9 | You can find the config YAML file [here](https://github.com/AuthMe/ConfigMe/blob/master/src/test/resources/demo/bean_demo_config.yml). 10 | Detailed information about using JavaBeans as properties can be found on the 11 | [Bean properties page](https://github.com/AuthMe/ConfigMe/wiki/Bean-properties) of the Wiki. 12 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/User.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | /** 9 | * Bean class for user data. 10 | */ 11 | public class User { 12 | 13 | private String name; 14 | private Location homeLocation; 15 | private Map savedLocations = new HashMap<>(); 16 | private Set nicknames = new HashSet<>(); 17 | 18 | public String getName() { 19 | return name; 20 | } 21 | 22 | public void setName(String name) { 23 | this.name = name; 24 | } 25 | 26 | public Location getHomeLocation() { 27 | return homeLocation; 28 | } 29 | 30 | public void setHomeLocation(Location homeLocation) { 31 | this.homeLocation = homeLocation; 32 | } 33 | 34 | public Map getSavedLocations() { 35 | return savedLocations; 36 | } 37 | 38 | public void setSavedLocations(Map savedLocations) { 39 | this.savedLocations = savedLocations; 40 | } 41 | 42 | public Set getNicknames() { 43 | return nicknames; 44 | } 45 | 46 | public void setNicknames(Set nicknames) { 47 | this.nicknames = nicknames; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/demo/beans/UserBase.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.demo.beans; 2 | 3 | import java.beans.Transient; 4 | 5 | /** 6 | * User base bean. 7 | */ 8 | public class UserBase { 9 | 10 | private User bobby; 11 | private User richie; 12 | private User lionel; 13 | private double version; 14 | private transient int build; 15 | 16 | public User getBobby() { 17 | return bobby; 18 | } 19 | 20 | public void setBobby(User bobby) { 21 | this.bobby = bobby; 22 | } 23 | 24 | public User getRichie() { 25 | return richie; 26 | } 27 | 28 | public void setRichie(User richie) { 29 | this.richie = richie; 30 | } 31 | 32 | public User getLionel() { 33 | return lionel; 34 | } 35 | 36 | public void setLionel(User lionel) { 37 | this.lionel = lionel; 38 | } 39 | 40 | public double getVersion() { 41 | return version; 42 | } 43 | 44 | public void setVersion(double version) { 45 | this.version = version; 46 | } 47 | 48 | @Transient 49 | public int getBuild() { 50 | return build; 51 | } 52 | 53 | public void setBuild(int build) { 54 | this.build = build; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/internal/StreamUtilsTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.internal; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.contains; 10 | import static org.hamcrest.Matchers.empty; 11 | 12 | /** 13 | * Test for {@link StreamUtils}. 14 | */ 15 | class StreamUtilsTest { 16 | 17 | @Test 18 | void shouldCreateStreamWithSameElement() { 19 | // given / when 20 | List list1 = StreamUtils.repeat("3", 3).collect(Collectors.toList()); 21 | List list2 = StreamUtils.repeat("1", 1).collect(Collectors.toList()); 22 | List list3 = StreamUtils.repeat("0", 0).collect(Collectors.toList()); 23 | 24 | // then 25 | assertThat(list1, contains("3", "3", "3")); 26 | assertThat(list2, contains("1")); 27 | assertThat(list3, empty()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/BooleanPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * Test for {@link BooleanProperty}. 19 | */ 20 | @ExtendWith(MockitoExtension.class) 21 | class BooleanPropertyTest { 22 | 23 | private static PropertyReader reader; 24 | 25 | @BeforeAll 26 | static void setUpConfiguration() { 27 | reader = mock(PropertyReader.class); 28 | when(reader.getObject("bool.path.test")).thenReturn(true); 29 | when(reader.getObject("bool.path.wrong")).thenReturn(null); 30 | } 31 | 32 | @Test 33 | void shouldGetBoolValue() { 34 | // given 35 | Property property = new BooleanProperty("bool.path.test", false); 36 | 37 | // when 38 | PropertyValue result = property.determineValue(reader); 39 | 40 | // then 41 | assertThat(result, isValidValueOf(true)); 42 | } 43 | 44 | @Test 45 | void shouldGetBoolDefault() { 46 | // given 47 | Property property = new BooleanProperty("bool.path.wrong", true); 48 | 49 | // when 50 | PropertyValue result = property.determineValue(reader); 51 | 52 | // then 53 | assertThat(result, isErrorValueOf(true)); 54 | } 55 | 56 | @Test 57 | void shouldReturnExportRepresentation() { 58 | // given 59 | Property property = new BooleanProperty("bool.path.test", true); 60 | 61 | // when 62 | Object exportValue = property.toExportValue(true); 63 | 64 | // then 65 | assertThat(exportValue, equalTo(true)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/DoublePropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.BDDMockito.given; 15 | 16 | /** 17 | * Test for {@link DoubleProperty}. 18 | */ 19 | @ExtendWith(MockitoExtension.class) 20 | class DoublePropertyTest { 21 | 22 | @Mock 23 | private PropertyReader reader; 24 | 25 | @Test 26 | void shouldReturnDoubleFromResource() { 27 | // given 28 | Property property = new DoubleProperty("test.path", 3.4); 29 | given(reader.getObject("test.path")).willReturn(-2508.346); 30 | 31 | // when 32 | PropertyValue result = property.determineValue(reader); 33 | 34 | // then 35 | assertThat(result, isValidValueOf(-2508.346)); 36 | } 37 | 38 | @Test 39 | void shouldReturnDefaultValue() { 40 | // given 41 | Property property = new DoubleProperty("property.path", 5.9); 42 | given(reader.getObject("property.path")).willReturn(null); 43 | 44 | // when 45 | PropertyValue result = property.determineValue(reader); 46 | 47 | // then 48 | assertThat(result, isErrorValueOf(5.9)); 49 | } 50 | 51 | @Test 52 | void shouldReturnValueAsExportValue() { 53 | // given 54 | Property property = new DoubleProperty("property.path", 4); 55 | double givenValue = 4.3456; 56 | 57 | // when 58 | Object exportValue = property.toExportValue(givenValue); 59 | 60 | // then 61 | assertThat(exportValue, equalTo(givenValue)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/EnumPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.mockito.junit.jupiter.MockitoExtension; 8 | 9 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 10 | import static ch.jalu.configme.TestUtils.isValidValueOf; 11 | import static org.hamcrest.MatcherAssert.assertThat; 12 | import static org.hamcrest.Matchers.equalTo; 13 | import static org.mockito.BDDMockito.given; 14 | import static org.mockito.Mockito.mock; 15 | 16 | /** 17 | * Test for {@link EnumProperty}. 18 | */ 19 | @ExtendWith(MockitoExtension.class) 20 | class EnumPropertyTest { 21 | 22 | @Test 23 | void shouldReturnCorrectEnumValue() { 24 | // given 25 | Property property = new EnumProperty<>("enum.path", TestEnum.class, TestEnum.ENTRY_C); 26 | PropertyReader reader = mock(PropertyReader.class); 27 | given(reader.getObject(property.getPath())).willReturn("Entry_B"); 28 | 29 | // when 30 | PropertyValue result = property.determineValue(reader); 31 | 32 | // then 33 | assertThat(result, isValidValueOf(TestEnum.ENTRY_B)); 34 | } 35 | 36 | @Test 37 | void shouldFallBackToDefaultForInvalidValue() { 38 | // given 39 | Property property = new EnumProperty<>("enum.path", TestEnum.class, TestEnum.ENTRY_C); 40 | PropertyReader reader = mock(PropertyReader.class); 41 | given(reader.getObject(property.getPath())).willReturn("Bogus"); 42 | 43 | // when 44 | PropertyValue result = property.determineValue(reader); 45 | 46 | // then 47 | assertThat(result, isErrorValueOf(TestEnum.ENTRY_C)); 48 | } 49 | 50 | @Test 51 | void shouldFallBackToDefaultForNonExistentValue() { 52 | // given 53 | Property property = new EnumProperty<>("enum.path", TestEnum.class, TestEnum.ENTRY_C); 54 | PropertyReader reader = mock(PropertyReader.class); 55 | given(reader.getObject(property.getPath())).willReturn(null); 56 | 57 | // when 58 | PropertyValue result = property.determineValue(reader); 59 | 60 | // then 61 | assertThat(result, isErrorValueOf(TestEnum.ENTRY_C)); 62 | } 63 | 64 | @Test 65 | void shouldExportAsEnumName() { 66 | // given 67 | Property property = new EnumProperty<>("my.test.path", TestEnum.class, TestEnum.ENTRY_A); 68 | 69 | // when 70 | Object exportObject = property.toExportValue(TestEnum.ENTRY_C); 71 | 72 | // then 73 | assertThat(exportObject, equalTo("ENTRY_C")); 74 | } 75 | 76 | private enum TestEnum { 77 | 78 | ENTRY_A, 79 | 80 | ENTRY_B, 81 | 82 | ENTRY_C 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/EnumSetPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import java.util.EnumSet; 11 | import java.util.Set; 12 | 13 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.mockito.BDDMockito.given; 16 | 17 | /** 18 | * Test for {@link EnumSetProperty}. 19 | */ 20 | @ExtendWith(MockitoExtension.class) 21 | class EnumSetPropertyTest { 22 | 23 | @Mock 24 | private PropertyReader reader; 25 | 26 | @Test 27 | void shouldReturnEnumSetDefaultValue() { 28 | // given 29 | EnumSet set = EnumSet.of(TestEnum.ENTRY_A); 30 | EnumSetProperty property = 31 | new EnumSetProperty<>("enum.path", TestEnum.class, set); 32 | given(reader.getObject(property.getPath())) 33 | .willReturn(null); 34 | 35 | // when 36 | PropertyValue> result = property.determineValue(reader); 37 | 38 | // then 39 | assertThat(result, isErrorValueOf(EnumSet.of(TestEnum.ENTRY_A))); 40 | } 41 | 42 | @Test 43 | void shouldReturnEnumSetDefaultValueFromArray() { 44 | // given 45 | EnumSetProperty property = 46 | new EnumSetProperty<>("enum.path", TestEnum.class, new TestEnum[]{TestEnum.ENTRY_B, TestEnum.ENTRY_C}); 47 | given(reader.getObject(property.getPath())) 48 | .willReturn(null); 49 | 50 | // when 51 | PropertyValue> result = property.determineValue(reader); 52 | 53 | // then 54 | assertThat(result, isErrorValueOf(EnumSet.of(TestEnum.ENTRY_B, TestEnum.ENTRY_C))); 55 | } 56 | 57 | private enum TestEnum { 58 | 59 | ENTRY_A, 60 | 61 | ENTRY_B, 62 | 63 | ENTRY_C 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/FloatPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.BDDMockito.given; 15 | 16 | /** 17 | * Test for {@link FloatProperty}. 18 | */ 19 | @ExtendWith(MockitoExtension.class) 20 | class FloatPropertyTest { 21 | 22 | @Mock 23 | private PropertyReader reader; 24 | 25 | @Test 26 | void shouldReturnFloatFromResource() { 27 | // given 28 | Property property = new FloatProperty("test.path", -4.11f); 29 | given(reader.getObject("test.path")).willReturn(-2508.346); 30 | 31 | // when 32 | PropertyValue result = property.determineValue(reader); 33 | 34 | // then 35 | assertThat(result, isValidValueOf(-2508.346f)); 36 | } 37 | 38 | @Test 39 | void shouldReturnDefaultValue() { 40 | // given 41 | Property property = new FloatProperty("property.path", 140f); 42 | given(reader.getObject("property.path")).willReturn(null); 43 | 44 | // when 45 | PropertyValue result = property.determineValue(reader); 46 | 47 | // then 48 | assertThat(result, isErrorValueOf(140f)); 49 | } 50 | 51 | @Test 52 | void shouldReturnValueAsExportValue() { 53 | // given 54 | Property property = new FloatProperty("property.path", 44f); 55 | float givenValue = 0.25f; 56 | 57 | // when 58 | Object exportValue = property.toExportValue(givenValue); 59 | 60 | // then 61 | assertThat(exportValue, equalTo(givenValue)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/InlineArrayPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.ConvertErrorRecorder; 4 | import ch.jalu.configme.properties.types.InlineArrayPropertyType; 5 | import ch.jalu.configme.resource.PropertyReader; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.arrayContaining; 12 | import static org.hamcrest.Matchers.equalTo; 13 | import static org.mockito.BDDMockito.given; 14 | import static org.mockito.Mockito.mock; 15 | 16 | /** 17 | * Test for {@link InlineArrayProperty}. 18 | */ 19 | @ExtendWith(MockitoExtension.class) 20 | class InlineArrayPropertyTest { 21 | 22 | @Test 23 | void shouldReturnArrayFromInlineConvertHelper() { 24 | // given 25 | BaseProperty property = new InlineArrayProperty<>( 26 | "inline_value", 27 | InlineArrayPropertyType.STRING, 28 | new String[] {"multiline", "message"} 29 | ); 30 | PropertyReader reader = mock(PropertyReader.class); 31 | given(reader.getObject("inline_value")).willReturn("hello\nkek"); 32 | 33 | // when 34 | String[] result = property.getFromReader(reader, new ConvertErrorRecorder()); 35 | 36 | // then 37 | assertThat(result, equalTo(new String[] {"hello", "kek"})); 38 | } 39 | 40 | @Test 41 | void shouldReturnConvertedValueAsExportValue() { 42 | // given 43 | Property property = new InlineArrayProperty<>( 44 | "array", 45 | InlineArrayPropertyType.STRING, 46 | new String[] {} 47 | ); 48 | String[] given = new String[] {"hello, chert", "how in hell?"}; 49 | 50 | // when / then 51 | assertThat(property.toExportValue(given), equalTo("hello, chert\nhow in hell?")); 52 | } 53 | 54 | @Test 55 | void shouldLogErrorForFailedConversion() { 56 | // given 57 | String value = "3,four,5"; 58 | InlineArrayProperty property = new InlineArrayProperty<>("path", InlineArrayPropertyType.INTEGER, new Integer[0]); 59 | ConvertErrorRecorder errorRecorder = new ConvertErrorRecorder(); 60 | PropertyReader reader = mock(PropertyReader.class); 61 | given(reader.getObject("path")).willReturn(value); 62 | 63 | // when 64 | Integer[] result = property.getFromReader(reader, errorRecorder); 65 | 66 | // then 67 | assertThat(result, arrayContaining(3, 5)); 68 | assertThat(errorRecorder.isFullyValid(), equalTo(false)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/IntegerPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * Test for {@link IntegerProperty}. 19 | */ 20 | @ExtendWith(MockitoExtension.class) 21 | class IntegerPropertyTest { 22 | 23 | private static PropertyReader reader; 24 | 25 | @BeforeAll 26 | static void setUpConfiguration() { 27 | reader = mock(PropertyReader.class); 28 | when(reader.getObject("int.path.test")).thenReturn(27); 29 | when(reader.getObject("int.path.wrong")).thenReturn(null); 30 | } 31 | 32 | @Test 33 | void shouldGetIntValue() { 34 | // given 35 | Property property = new IntegerProperty("int.path.test", 3); 36 | 37 | // when 38 | PropertyValue result = property.determineValue(reader); 39 | 40 | // then 41 | assertThat(result, isValidValueOf(27)); 42 | } 43 | 44 | @Test 45 | void shouldGetIntDefault() { 46 | // given 47 | Property property = new IntegerProperty("int.path.wrong", -10); 48 | 49 | // when 50 | PropertyValue result = property.determineValue(reader); 51 | 52 | // then 53 | assertThat(result, isErrorValueOf(-10)); 54 | } 55 | 56 | @Test 57 | void shouldReturnValueForExport() { 58 | // given 59 | Property property = new IntegerProperty("some.path", -5); 60 | 61 | // when 62 | Object exportValue = property.toExportValue(45); 63 | 64 | // then 65 | assertThat(exportValue, equalTo(45)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/LongPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * Test for {@link LongProperty}. 19 | */ 20 | @ExtendWith(MockitoExtension.class) 21 | class LongPropertyTest { 22 | 23 | private static PropertyReader reader; 24 | 25 | @BeforeAll 26 | static void setUpConfiguration() { 27 | reader = mock(PropertyReader.class); 28 | when(reader.getObject("long.path.test")).thenReturn(30L); 29 | when(reader.getObject("long.path.wrong")).thenReturn(null); 30 | } 31 | 32 | @Test 33 | void shouldGetLongValue() { 34 | // given 35 | Property property = new LongProperty("long.path.test", 5L); 36 | 37 | // when 38 | PropertyValue result = property.determineValue(reader); 39 | 40 | // then 41 | assertThat(result, isValidValueOf(30L)); 42 | } 43 | 44 | @Test 45 | void shouldGetLongDefault() { 46 | // given 47 | Property property = new LongProperty("long.path.wrong", -10L); 48 | 49 | // when 50 | PropertyValue result = property.determineValue(reader); 51 | 52 | // then 53 | assertThat(result, isErrorValueOf(-10L)); 54 | } 55 | 56 | @Test 57 | void shouldReturnValueForExport() { 58 | // given 59 | Property property = new LongProperty("some.path", -10L); 60 | 61 | // when 62 | Object exportValue = property.toExportValue(50L); 63 | 64 | // then 65 | assertThat(exportValue, equalTo(50L)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/ShortPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.convertresult.PropertyValue; 4 | import ch.jalu.configme.resource.PropertyReader; 5 | import org.junit.jupiter.api.BeforeAll; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.mockito.junit.jupiter.MockitoExtension; 9 | 10 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 11 | import static ch.jalu.configme.TestUtils.isValidValueOf; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.mockito.Mockito.mock; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * Test for {@link ShortProperty}. 19 | */ 20 | @ExtendWith(MockitoExtension.class) 21 | class ShortPropertyTest { 22 | 23 | private static PropertyReader reader; 24 | 25 | @BeforeAll 26 | static void setUpConfiguration() { 27 | reader = mock(PropertyReader.class); 28 | when(reader.getObject("short.path.test")).thenReturn((short) 15); 29 | when(reader.getObject("short.path.wrong")).thenReturn(null); 30 | } 31 | 32 | @Test 33 | void shouldGetValueFromReader() { 34 | // given 35 | Property property = new ShortProperty("short.path.test", (short) 10); 36 | 37 | // when 38 | PropertyValue result = property.determineValue(reader); 39 | 40 | // then 41 | assertThat(result, isValidValueOf((short) 15)); 42 | } 43 | 44 | @Test 45 | void shouldReturnDefaultValue() { 46 | // given 47 | Property property = new ShortProperty("short.path.wrong", (short) -5); 48 | 49 | // when 50 | PropertyValue result = property.determineValue(reader); 51 | 52 | // then 53 | assertThat(result, isErrorValueOf((short) -5)); 54 | } 55 | 56 | @Test 57 | void shouldReturnValueForExport() { 58 | // given 59 | Property property = new ShortProperty("some.path", (short) -3); 60 | 61 | // when 62 | Object exportValue = property.toExportValue((short) 25); 63 | 64 | // then 65 | assertThat(exportValue, equalTo((short) 25)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/TypeBasedPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties; 2 | 3 | import ch.jalu.configme.properties.types.NumberType; 4 | import ch.jalu.configme.properties.types.PropertyType; 5 | import ch.jalu.configme.properties.types.StringType; 6 | import ch.jalu.configme.resource.PropertyReader; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.extension.ExtendWith; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.jupiter.MockitoExtension; 11 | 12 | import static ch.jalu.configme.TestUtils.isErrorValueOf; 13 | import static ch.jalu.configme.TestUtils.isValidValueOf; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.hamcrest.Matchers.equalTo; 16 | import static org.hamcrest.Matchers.sameInstance; 17 | import static org.mockito.BDDMockito.given; 18 | 19 | /** 20 | * Test for {@link TypeBasedProperty}. 21 | */ 22 | @ExtendWith(MockitoExtension.class) 23 | class TypeBasedPropertyTest { 24 | 25 | @Mock 26 | private PropertyReader reader; 27 | 28 | @Test 29 | void shouldReturnValueFromResource() { 30 | // given 31 | Property property = new TypeBasedProperty<>("common.path", StringType.STRING, "default"); 32 | given(reader.getObject("common.path")).willReturn("some string"); 33 | 34 | // when / then 35 | assertThat(property.determineValue(reader), isValidValueOf("some string")); 36 | } 37 | 38 | @Test 39 | void shouldReturnDefaultValue() { 40 | // given 41 | Property property = new TypeBasedProperty<>("common.path", StringType.STRING, "default"); 42 | 43 | // when / then 44 | assertThat(property.determineValue(reader), isErrorValueOf("default")); 45 | } 46 | 47 | @Test 48 | void shouldReturnValueAsExportValue() { 49 | // given 50 | Property property = new TypeBasedProperty<>("common.path", StringType.STRING, "default"); 51 | String given = "given string"; 52 | 53 | // when / then 54 | assertThat(property.toExportValue(given), equalTo(given)); 55 | } 56 | 57 | @Test 58 | void shouldReturnPropertyType() { 59 | // given 60 | TypeBasedProperty property = new TypeBasedProperty<>("common.size", NumberType.INTEGER, 5); 61 | 62 | // when 63 | PropertyType type = property.getType(); 64 | 65 | // then 66 | assertThat(type, sameInstance(NumberType.INTEGER)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/properties/builder/PropertyBuilderUtilsTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.properties.builder; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | import static org.hamcrest.Matchers.equalTo; 7 | import static org.junit.jupiter.api.Assertions.assertThrows; 8 | 9 | /** 10 | * Test for {@link PropertyBuilderUtils}. 11 | */ 12 | class PropertyBuilderUtilsTest { 13 | 14 | @Test 15 | void shouldThrowForNullPath() { 16 | // given / when 17 | IllegalStateException ex = assertThrows(IllegalStateException.class, 18 | () -> PropertyBuilderUtils.requireNonNullPath(null)); 19 | 20 | // then 21 | assertThat(ex.getMessage(), equalTo("The path of the property must be defined")); 22 | } 23 | 24 | @Test 25 | void shouldAcceptNonNullPath() { 26 | // given 27 | String path = "test"; 28 | 29 | // when 30 | PropertyBuilderUtils.requireNonNullPath(path); 31 | 32 | // then - no exception 33 | } 34 | 35 | @Test 36 | void shouldNotThrowIfDefaultValueIsEmpty() { 37 | // given / when 38 | PropertyBuilderUtils.verifyDefaultValueIsEmpty(true); 39 | 40 | // then - no exception 41 | } 42 | 43 | @Test 44 | void shouldThrowIfDefaultValueIsNotEmpty() { 45 | // given / when 46 | IllegalStateException ex = assertThrows(IllegalStateException.class, 47 | () -> PropertyBuilderUtils.verifyDefaultValueIsEmpty(false)); 48 | 49 | // then 50 | assertThat(ex.getMessage(), equalTo("Default values have already been defined! Use addToDefaultValue to add entries individually")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/resource/YamlFileResourceOptionsTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource; 2 | 3 | import ch.jalu.configme.resource.PropertyPathTraverser.PathElement; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.function.ToIntFunction; 8 | 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.hamcrest.Matchers.equalTo; 11 | import static org.hamcrest.Matchers.nullValue; 12 | 13 | /** 14 | * Test for {@link YamlFileResourceOptions}. 15 | */ 16 | class YamlFileResourceOptionsTest { 17 | 18 | @Test 19 | void shouldKeepConfiguredValues() { 20 | // given 21 | ToIntFunction lineFunction = PathElement::getIndentationLevel; 22 | 23 | // when 24 | YamlFileResourceOptions options = YamlFileResourceOptions.builder() 25 | .numberOfLinesBeforeFunction(lineFunction) 26 | .charset(StandardCharsets.UTF_16BE) 27 | .indentationSize(2) 28 | .build(); 29 | 30 | // then 31 | assertThat(options.getCharset(), equalTo(StandardCharsets.UTF_16BE)); 32 | assertThat(options.getIndentFunction(), equalTo(lineFunction)); 33 | PathElement pathElement = new PathElement(3, "test", "test", false); 34 | assertThat(options.getNumberOfEmptyLinesBefore(pathElement), equalTo(3)); 35 | assertThat(options.getIndentationSize(), equalTo(2)); 36 | } 37 | 38 | @Test 39 | void shouldCreateOptionsWithDefaults() { 40 | // given / when 41 | YamlFileResourceOptions options = YamlFileResourceOptions.builder().build(); 42 | 43 | // then 44 | assertThat(options.getCharset(), equalTo(StandardCharsets.UTF_8)); 45 | assertThat(options.getIndentFunction(), nullValue()); 46 | assertThat(options.getIndentationSize(), equalTo(4)); 47 | PathElement pathElement = new PathElement(3, "test", "test", false); 48 | assertThat(options.getNumberOfEmptyLinesBefore(pathElement), equalTo(0)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/resource/YamlFileResourceRootMapPropertyTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.TestUtils; 5 | import ch.jalu.configme.configurationdata.ConfigurationData; 6 | import ch.jalu.configme.configurationdata.ConfigurationDataBuilder; 7 | import ch.jalu.configme.properties.MapProperty; 8 | import ch.jalu.configme.properties.Property; 9 | import ch.jalu.configme.properties.convertresult.PropertyValue; 10 | import ch.jalu.configme.properties.types.BeanPropertyType; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.io.TempDir; 13 | 14 | import java.nio.file.Path; 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import static org.hamcrest.MatcherAssert.assertThat; 22 | import static org.hamcrest.Matchers.equalTo; 23 | import static org.hamcrest.collection.IsIterableContainingInOrder.contains; 24 | 25 | class YamlFileResourceRootMapPropertyTest { 26 | 27 | @TempDir 28 | public Path temporaryFolder; 29 | 30 | @Test 31 | void shouldWriteAndReadFile() { 32 | //given 33 | Path tempFolder = TestUtils.createTemporaryFile(temporaryFolder); 34 | YamlFileResource resource = new YamlFileResource(tempFolder); 35 | ConfigurationData configurationData = ConfigurationDataBuilder.createConfiguration(SampleConfig.class); 36 | 37 | Map mapProperty = new HashMap<>(); 38 | mapProperty.put("props", new InnerProperties()); 39 | mapProperty.get("props").setProps(Arrays.asList("foo", "bar")); 40 | 41 | configurationData.setValue(SampleConfig.MAP_PROPERTY, mapProperty); 42 | resource.exportProperties(configurationData); 43 | 44 | //when 45 | PropertyValue> actualPropertyValue = 46 | SampleConfig.MAP_PROPERTY.determineValue(resource.createReader()); 47 | 48 | //then 49 | assertThat(actualPropertyValue.isValidInResource(), equalTo(true)); 50 | assertThat(actualPropertyValue.getValue().keySet(), contains("props")); 51 | assertThat(actualPropertyValue.getValue().get("props").getProps(), contains("foo", "bar")); 52 | } 53 | 54 | public static final class SampleConfig implements SettingsHolder { 55 | 56 | public static final Property> MAP_PROPERTY = new MapProperty<>( 57 | "", 58 | BeanPropertyType.of(InnerProperties.class) 59 | ); 60 | 61 | private SampleConfig() { 62 | } 63 | } 64 | 65 | public static class InnerProperties { 66 | private List props = new ArrayList<>(); 67 | 68 | public List getProps() { 69 | return props; 70 | } 71 | 72 | public void setProps(List props) { 73 | this.props = props; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/resource/YamlFileResourceTopCommentTest.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource; 2 | 3 | import ch.jalu.configme.SettingsManagerBuilder; 4 | import ch.jalu.configme.resource.rootcommentsamples.GroupPropertyHolder; 5 | import ch.jalu.configme.resource.rootcommentsamples.TestConfig; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.jupiter.api.io.TempDir; 9 | 10 | import java.io.IOException; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | 14 | import static ch.jalu.configme.TestUtils.createTemporaryFile; 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.contains; 17 | 18 | /** 19 | * Tests that comments on the root path are included into the YAML export. 20 | * 21 | * @see Issue #25 22 | */ 23 | class YamlFileResourceTopCommentTest { 24 | 25 | @TempDir 26 | public Path temporaryFolder; 27 | 28 | private Path file; 29 | 30 | @BeforeEach 31 | void initEmptyFile() { 32 | file = createTemporaryFile(temporaryFolder); 33 | } 34 | 35 | @Test 36 | void shouldIncludeCommentFromAnnotation() throws IOException { 37 | // given 38 | PropertyResource resource = new YamlFileResource(file); 39 | 40 | // when 41 | SettingsManagerBuilder.withResource(resource) 42 | .configurationData(GroupPropertyHolder.class) 43 | .useDefaultMigrationService() 44 | .create(); 45 | 46 | // then 47 | assertThat(Files.readAllLines(file), contains( 48 | "# Group configuration number", 49 | "worlds:", 50 | "- world", 51 | "default-gamemode: CREATIVE" 52 | )); 53 | } 54 | 55 | @Test 56 | void shouldIncludeRootCommentFromSectionCommentsMethod() throws IOException { 57 | // given 58 | PropertyResource resource = new YamlFileResource(file); 59 | 60 | // when 61 | SettingsManagerBuilder.withResource(resource) 62 | .configurationData(TestConfig.class) 63 | .useDefaultMigrationService() 64 | .create(); 65 | 66 | // then 67 | assertThat(Files.readAllLines(file), contains( 68 | "# Root comment", 69 | "# 'some' Section", 70 | "# Explanation for 'some'", 71 | "some:", 72 | " # Integer property", 73 | " test: 4", 74 | " # Other header", 75 | " other:", 76 | " property: hello" 77 | )); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/resource/rootcommentsamples/GroupPropertyHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource.rootcommentsamples; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.beanmapper.worldgroup.GameMode; 6 | import ch.jalu.configme.beanmapper.worldgroup.Group; 7 | import ch.jalu.configme.properties.BeanProperty; 8 | import ch.jalu.configme.properties.Property; 9 | 10 | import java.util.Collections; 11 | 12 | public final class GroupPropertyHolder implements SettingsHolder { 13 | 14 | @Comment("Group configuration number") 15 | public static final Property GROUP = new BeanProperty<>("", Group.class, buildDefaultGroup()); 16 | 17 | private GroupPropertyHolder() { 18 | } 19 | 20 | private static Group buildDefaultGroup() { 21 | Group group = new Group(); 22 | group.setWorlds(Collections.singletonList("world")); 23 | group.setDefaultGamemode(GameMode.CREATIVE); 24 | return group; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/resource/rootcommentsamples/TestConfig.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.resource.rootcommentsamples; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 6 | import ch.jalu.configme.properties.Property; 7 | 8 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 9 | 10 | public final class TestConfig implements SettingsHolder { 11 | 12 | @Comment("Integer property") 13 | public static final Property INT_PROPERTY = newProperty("some.test", 4); 14 | 15 | public static final Property STRING_PROPERTY = newProperty("some.other.property", "hello"); 16 | 17 | private TestConfig() { 18 | } 19 | 20 | @Override 21 | public void registerComments(CommentsConfiguration conf) { 22 | conf.setComment("", "Root comment"); 23 | conf.setComment("some", "'some' Section", "Explanation for 'some'"); 24 | conf.setComment("some.other", "Other header"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/ClassWithPrivatePropertyField.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.Property; 5 | 6 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 7 | 8 | public class ClassWithPrivatePropertyField implements SettingsHolder { 9 | 10 | private static final Property PRIVATE_INT_PROPERTY = newProperty("int", 4); 11 | 12 | public static Property getPrivatePropertyValue() { 13 | return PRIVATE_INT_PROPERTY; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/TestEnum.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples; 2 | 3 | /** 4 | * Test enum used in {@link TestConfiguration}. 5 | */ 6 | public enum TestEnum { 7 | 8 | FIRST, 9 | 10 | SECOND, 11 | 12 | THIRD, 13 | 14 | FOURTH 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/TestVersionConfiguration.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.properties.Property; 6 | 7 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 8 | 9 | 10 | /** 11 | * Sample properties for testing versioning purposes. 12 | *

13 | * This class represents the next version of the following config: 14 | * version: 1 15 | * potatoes: 4 16 | * tomatoes: 10 17 | *

18 | * 19 | * The following settings holder is different and needs a migration! 20 | *

21 | * From version 1 to 2 and: 22 | * - from potatoes: 4 ----> to shelf.potatoes: 4 23 | * - from tomatoes: 10 ----> to shelf.tomatoes: 10 24 | *

25 | * So it keeps the same values as the old configuration! 26 | * 27 | * @author gamerover98 28 | */ 29 | public final class TestVersionConfiguration implements SettingsHolder { 30 | 31 | @Comment("The version number") 32 | public static final Property VERSION_NUMBER = 33 | newProperty("version", 2); 34 | 35 | public static final Property SHELF_POTATOES = 36 | newProperty("shelf.potatoes", 40); 37 | 38 | public static final Property SHELF_TOMATOES = 39 | newProperty("shelf.tomatoes", 100); 40 | 41 | private TestVersionConfiguration() { 42 | // nothing to do. 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/beanannotations/AnnotatedEntry.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.beanannotations; 2 | 3 | import ch.jalu.configme.beanmapper.ExportName; 4 | 5 | /** 6 | * "Entry" bean class with annotated properties. 7 | */ 8 | public class AnnotatedEntry { 9 | 10 | private long id; 11 | @ExportName("has-id") 12 | private boolean hasId; 13 | 14 | public long getId() { 15 | return id; 16 | } 17 | 18 | public void setId(long id) { 19 | this.id = id; 20 | } 21 | 22 | public boolean getHasId() { 23 | return hasId; 24 | } 25 | 26 | public void setHasId(boolean hasId) { 27 | this.hasId = hasId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/beanannotations/BeanWithEmptyName.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.beanannotations; 2 | 3 | import ch.jalu.configme.beanmapper.ExportName; 4 | 5 | /** 6 | * Sample bean where an export name is null. 7 | */ 8 | public class BeanWithEmptyName { 9 | 10 | @ExportName(value = "") 11 | private String author; 12 | private String title; 13 | private int edition; 14 | 15 | public String getAuthor() { 16 | return author; 17 | } 18 | 19 | public void setAuthor(String author) { 20 | this.author = author; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public int getEdition() { 32 | return edition; 33 | } 34 | 35 | public void setEdition(int edition) { 36 | this.edition = edition; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/beanannotations/BeanWithExportName.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.beanannotations; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.beanmapper.ExportName; 5 | 6 | public class BeanWithExportName { 7 | 8 | @Comment("name_com") 9 | @ExportName("s_name") 10 | private String name; 11 | 12 | @Comment("active_com") 13 | @ExportName("b_active") 14 | private boolean active; 15 | 16 | @Comment("size_com") 17 | @ExportName("i_size") 18 | private int size; 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public boolean isActive() { 29 | return active; 30 | } 31 | 32 | public void setActive(boolean active) { 33 | this.active = active; 34 | } 35 | 36 | public int getSize() { 37 | return size; 38 | } 39 | 40 | public void setSize(int size) { 41 | this.size = size; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/beanannotations/BeanWithExportNameExtension.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.beanannotations; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.beanmapper.ExportName; 5 | 6 | public class BeanWithExportNameExtension extends BeanWithExportName { 7 | 8 | @Comment("weight_com") 9 | @ExportName("d_weight") 10 | private double weight; 11 | 12 | public double getWeight() { 13 | return weight; 14 | } 15 | 16 | public void setWeight(double weight) { 17 | this.weight = weight; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/beanannotations/BeanWithNameClash.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.beanannotations; 2 | 3 | import ch.jalu.configme.beanmapper.ExportName; 4 | 5 | /** 6 | * Sample bean with two properties declared with the same name. 7 | */ 8 | public class BeanWithNameClash { 9 | 10 | private String location; 11 | @ExportName("threshold") 12 | private String otherProperty; 13 | private int threshold; 14 | 15 | public String getLocation() { 16 | return location; 17 | } 18 | 19 | public void setLocation(String location) { 20 | this.location = location; 21 | } 22 | 23 | public String getOtherProperty() { 24 | return otherProperty; 25 | } 26 | 27 | public void setOtherProperty(String otherProperty) { 28 | this.otherProperty = otherProperty; 29 | } 30 | 31 | public int getThreshold() { 32 | return threshold; 33 | } 34 | 35 | public void setThreshold(int threshold) { 36 | this.threshold = threshold; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/inheritance/Child.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.inheritance; 2 | 3 | import java.beans.Transient; 4 | 5 | /** 6 | * Child class. 7 | */ 8 | public class Child extends Middle { 9 | 10 | private int importance; 11 | 12 | @Override 13 | public boolean isTemporary() { 14 | return super.isTemporary(); 15 | } 16 | 17 | @Override 18 | @Transient(false) 19 | public void setTemporary(boolean temporary) { 20 | super.setTemporary(temporary); 21 | } 22 | 23 | public int getImportance() { 24 | return importance; 25 | } 26 | 27 | public void setImportance(int importance) { 28 | this.importance = importance; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/inheritance/Middle.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.inheritance; 2 | 3 | /** 4 | * Middle class. 5 | */ 6 | public class Middle extends Parent { 7 | 8 | private String name; 9 | private float ratio; 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | public void setName(String name) { 16 | this.name = name; 17 | } 18 | 19 | public float getRatio() { 20 | return ratio; 21 | } 22 | 23 | public void setRatio(float ratio) { 24 | this.ratio = ratio; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/inheritance/Parent.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.inheritance; 2 | 3 | import java.beans.Transient; 4 | 5 | /** 6 | * Parent class. 7 | */ 8 | public class Parent { 9 | 10 | private long id; 11 | private transient boolean temporary; 12 | 13 | public long getId() { 14 | return id; 15 | } 16 | 17 | public void setId(long id) { 18 | this.id = id; 19 | } 20 | 21 | public boolean isTemporary() { 22 | return temporary; 23 | } 24 | 25 | @Transient 26 | public void setTemporary(boolean temporary) { 27 | this.temporary = temporary; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/FullyValidSettingsHolder1.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.beanmapper.worldgroup.GameMode; 6 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 7 | import ch.jalu.configme.properties.Property; 8 | 9 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 10 | 11 | public final class FullyValidSettingsHolder1 implements SettingsHolder { 12 | 13 | @Comment("Int property") 14 | public static final Property INT_PROPERTY = 15 | newProperty("test.foo", 3); 16 | 17 | @Comment("String prop") 18 | public static final Property STRING_PROPERTY = 19 | newProperty("test.str", "default"); 20 | 21 | @Comment("Enum property. Possible values: CREATIVE, SURVIVAL") 22 | public static final Property GAME_MODE_PROPERTY = 23 | newProperty(GameMode.class, "test.gamemode", GameMode.SURVIVAL); 24 | 25 | private FullyValidSettingsHolder1() { 26 | } 27 | 28 | @Override 29 | public void registerComments(CommentsConfiguration conf) { 30 | conf.setComment("test", "Comment for test section", "Test section comment pt. 2"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/FullyValidSettingsHolder2.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.properties.ListProperty; 6 | import ch.jalu.configme.properties.Property; 7 | import ch.jalu.configme.properties.StringListProperty; 8 | 9 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 10 | 11 | public final class FullyValidSettingsHolder2 implements SettingsHolder { 12 | 13 | @Comment({"Double prop", "Double propppp"}) 14 | public static final Property DOUBLE_PROPERTY = 15 | newProperty("all.double", 3.0); 16 | 17 | @Comment("The list goes skrrrah") 18 | public static final ListProperty LIST_PROPERTY = 19 | new StringListProperty("all.list", "The", "default", "elements"); 20 | 21 | private FullyValidSettingsHolder2() { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/MissingCommentsHolder.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.properties.IntegerProperty; 6 | import ch.jalu.configme.properties.Property; 7 | 8 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 9 | 10 | public class MissingCommentsHolder implements SettingsHolder { 11 | 12 | public static final Property STR_PROPERTY = newProperty("lorem.ipsum", "d"); 13 | 14 | public static final IntegerProperty INT_PROPERTY = new IntegerProperty("lorem.dolor", 3); 15 | 16 | @Comment("A comment") 17 | public static final Property DBL_PROPERTY = newProperty("lorem.amet", 3.40); 18 | 19 | private MissingCommentsHolder() { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/SettingsHolderWithEnumPropertyComments.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.beanmapper.worldgroup.GameMode; 6 | import ch.jalu.configme.properties.Property; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 11 | 12 | public class SettingsHolderWithEnumPropertyComments implements SettingsHolder { 13 | 14 | @Comment("Time unit (SECONDS, MINUTES, HOURS)") 15 | public static final Property TIME_UNIT_PROP = newProperty(TimeUnit.class, "sample.timeUnit", TimeUnit.SECONDS); 16 | 17 | public static final Property GAME_MODE = newProperty(GameMode.class, "sample.gameMode", GameMode.SURVIVAL); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/SettingsHolderWithInvalidConstants.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.SettingsHolder; 4 | import ch.jalu.configme.properties.DoubleProperty; 5 | import ch.jalu.configme.properties.Property; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import static ch.jalu.configme.properties.PropertyInitializer.newListProperty; 11 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 12 | 13 | public class SettingsHolderWithInvalidConstants implements SettingsHolder { 14 | 15 | public /*static*/ final DoubleProperty DBL_PROP = new DoubleProperty("com.test", -44); 16 | 17 | public static final Property STR_PROP = newProperty("com.foo", ""); 18 | 19 | public static /*final*/ Property> STRLIST = newListProperty("com.bar"); 20 | 21 | /*public*/ static final Property TIME_UNIT = newProperty(TimeUnit.class, "com.timeUnit", TimeUnit.SECONDS); 22 | 23 | private SettingsHolderWithInvalidConstants() { 24 | } 25 | 26 | // used for test ensuring classes only have a sole no-args private constructor 27 | private SettingsHolderWithInvalidConstants(boolean other) { 28 | } 29 | 30 | public static class Child extends SettingsHolderWithInvalidConstants { 31 | 32 | private final Property strProp = null; 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/ch/jalu/configme/samples/settingsholders/SettingsHolderWithVariousCommentLengths.java: -------------------------------------------------------------------------------- 1 | package ch.jalu.configme.samples.settingsholders; 2 | 3 | import ch.jalu.configme.Comment; 4 | import ch.jalu.configme.SettingsHolder; 5 | import ch.jalu.configme.configurationdata.CommentsConfiguration; 6 | import ch.jalu.configme.properties.Property; 7 | 8 | import static ch.jalu.configme.properties.PropertyInitializer.newProperty; 9 | 10 | public class SettingsHolderWithVariousCommentLengths implements SettingsHolder { 11 | 12 | @Comment("Length 20 characters") 13 | public static final Property WITH_20_LEN = newProperty("comment.20", "zwänzg"); 14 | 15 | @Comment("Short") 16 | public static final Property WITH_5_LEN = newProperty("comment.5", "foif"); 17 | 18 | @Comment("The length on the property is exactly 40") 19 | public static final Property WITH_40_LEN = newProperty("comment.40", "vierzg"); 20 | 21 | @Comment("Finally, text of 25 chars") 22 | public static final Property WITH_25_LEN = newProperty("comment.25", "foifezwänzg"); 23 | 24 | private SettingsHolderWithVariousCommentLengths() { 25 | } 26 | 27 | @Override 28 | public void registerComments(CommentsConfiguration conf) { 29 | conf.setComment("comment", "This text has length of thirty"); 30 | conf.setComment("", "root"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/commands.yml: -------------------------------------------------------------------------------- 1 | commandconfig: 2 | duration: 13 3 | commands: 4 | save: 5 | command: save 6 | execution: 7 | executor: CONSOLE 8 | importance: 1.0 9 | privileges: 10 | - 'action.save' 11 | refresh: 12 | command: refresh 13 | arguments: 14 | - force 15 | - async 16 | execution: 17 | executor: console 18 | importance: 0.4 19 | optional: true 20 | privileges: 21 | - 'page.view' 22 | - 'action.refresh' 23 | open: 24 | command: open 25 | arguments: 26 | - f 27 | - x 28 | - z 29 | execution: 30 | executor: USER 31 | importance: 0.7 32 | privileges: 33 | - 'page.view' 34 | othersection: 35 | a: 1 36 | b: 'test' 37 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/commands_invalid.yml: -------------------------------------------------------------------------------- 1 | commandconfig: 2 | duration: 13 3 | commands: 4 | save: 5 | # missing command, which is mandatory 6 | execution: 7 | executor: CONSOLE 8 | importance: 1.0 9 | privileges: 10 | - 'action.save' 11 | refresh: 12 | command: refresh 13 | arguments: 14 | - force 15 | - async 16 | execution: 17 | executor: console 18 | importance: 0.4 19 | optional: true 20 | privileges: 21 | - 'page.view' 22 | - 'action.refresh' 23 | open: 24 | command: open 25 | arguments: 26 | - f 27 | - x 28 | - z 29 | execution: 30 | executor: USER 31 | importance: 0.7 32 | privileges: 33 | - 'page.view' 34 | cancel: 35 | command: cancel 36 | arguments: 'wrong type' # optional argument with wrong type -> fall back to default 37 | execution: 38 | executor: USER 39 | importance: 0.7 40 | privileges: # Weird values here, but our mapping to string is quite flexible 41 | - 'action.cancel' 42 | - true 43 | - 1.23 44 | - 45 | - nested 46 | - list 47 | - uh oh! 48 | broadcast: 49 | command: broadcast 50 | execution: 51 | executor: USER 52 | importance: 'high' # wrong value for mandatory property 53 | privileges: 54 | - 'action.cancel' 55 | othersection: 56 | a: 1 57 | b: 'test' 58 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/commands_invalid_2.yml: -------------------------------------------------------------------------------- 1 | commandconfig: 2 | duration: 13 3 | commands: 4 | - 'Hello' 5 | - 'I should be a map' 6 | - 'but I''m a list!' 7 | othersection: 8 | a: 1 9 | b: 'test' 10 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/commands_root_path.yml: -------------------------------------------------------------------------------- 1 | duration: 13 2 | commands: 3 | save: 4 | command: save 5 | execution: 6 | executor: CONSOLE 7 | importance: 1.0 8 | privileges: 9 | - 'action.open' 10 | - 'action.save' 11 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/nested_chat_component.yml: -------------------------------------------------------------------------------- 1 | message-key: 2 | color: blue 3 | text: outside 4 | extra: 5 | - color: green 6 | text: inner1 7 | - color: blue 8 | text: inner2 9 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/nested_chat_component_complex_expected.yml: -------------------------------------------------------------------------------- 1 | message-key: 2 | color: green 3 | text: outside 4 | extra: 5 | - color: yellow 6 | text: inner1 7 | extra: [] 8 | - color: blue 9 | text: inner2 10 | extra: 11 | - color: red 12 | text: level2 text 13 | extra: [] 14 | # Optional: additional info 15 | conditionalElem: 16 | color: orange 17 | text: orange extension 18 | extra: [] 19 | conditionals: 20 | low: 21 | color: white 22 | text: low text 23 | extra: [] 24 | conditionals: {} 25 | med: 26 | color: gray 27 | text: med text 28 | extra: 29 | - color: green 30 | text: med child 31 | extra: [] 32 | conditionals: {} 33 | high: 34 | color: black 35 | text: high text 36 | extra: [] 37 | # Optional: additional info 38 | conditionalElem: 39 | color: teal 40 | text: teal addition 41 | extra: [] 42 | conditionals: {} 43 | italic: false 44 | bold: true 45 | conditionals: {} 46 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/optionalproperties/complex-commands.yml: -------------------------------------------------------------------------------- 1 | commandconfig: 2 | duration: 13 3 | commands: 4 | greet: 5 | command: 'hello $user' 6 | arguments: 7 | - 'user' 8 | execution: 9 | executor: CONSOLE 10 | importance: 0.5 11 | privileges: 12 | - 'user.greet' 13 | nameStartsWith: 'user_' 14 | block_invalid: 15 | command: reject_connection 16 | execution: 17 | executor: CONSOLE 18 | importance: 1.0 19 | privileges: 20 | - 'system.kick' 21 | nameHasLength: 80 22 | testEnumProperty: SECOND 23 | log_admin: 24 | command: 'log $name' 25 | arguments: 26 | - name 27 | execution: 28 | executor: console 29 | importance: 0.8 30 | optional: true 31 | privileges: [] 32 | doubleOptional: 0.531 33 | launch: 34 | command: 'start app' 35 | arguments: [] 36 | execution: 37 | executor: 'USER' 38 | importance: 1.0 39 | privileges: 40 | - 'app' 41 | testEnumProperty: 'fourth' 42 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/typeissues/collectionconfig.yml: -------------------------------------------------------------------------------- 1 | name: 'test' 2 | collection: 3 | - 12.0 4 | - 14.1 5 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/typeissues/mapconfig.yml: -------------------------------------------------------------------------------- 1 | name: 'config with map' 2 | map: 3 | 12: 14 4 | 14: 12 5 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/worlds.yml: -------------------------------------------------------------------------------- 1 | groups: 2 | default: 3 | worlds: 4 | - world 5 | - world_nether 6 | - world_the_end 7 | default-gamemode: SURVIVAL 8 | creative: 9 | worlds: 10 | - creative 11 | default-gamemode: CREATIVE 12 | -------------------------------------------------------------------------------- /src/test/resources/beanmapper/worlds_invalid.yml: -------------------------------------------------------------------------------- 1 | groups: 2 | default: 3 | worlds: 2 4 | default-gamemode: SURVIVAL 5 | creative: 6 | worlds: 7 | - creative 8 | default-gamemode: CREATIVE 9 | adventure: 10 | worlds: 11 | - adventure 12 | default-gamemode: INVALID_ENTRY 13 | -------------------------------------------------------------------------------- /src/test/resources/charsets/iso-8859-1_sample.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthMe/ConfigMe/36499245ce5f61735445d28d0e1f984c1569fd48/src/test/resources/charsets/iso-8859-1_sample.yml -------------------------------------------------------------------------------- /src/test/resources/charsets/utf8_sample.yml: -------------------------------------------------------------------------------- 1 | first: 'Санкт-Петербург' 2 | second: 'շերտիկներն' 3 | third: '错误的密码' 4 | -------------------------------------------------------------------------------- /src/test/resources/config-difficult-values.yml: -------------------------------------------------------------------------------- 1 | # Test config file with some "difficult" values 2 | test: 3 | duration: 20.102 4 | systemName: 'A ''test'' name' 5 | sample: 6 | ratio: 7 | order: Fourth 8 | fields: 9 | - Australia\ 10 | - ' Burundi''' 11 | - 'Colombia? 12 | 13 | ''''' 14 | # The last element above represents "Colombia?\n''" 15 | version: -1337 16 | features: 17 | boring: 18 | # YAML allows both "yes"/"no" and "true"/"false" for expressing booleans 19 | skip: no 20 | colors: 21 | - 'it''s a difficult string!' 22 | - | 23 | gray 24 | with new lines 25 | # dustLevel: 8 <-- missing property triggering rewrite 26 | cool: 27 | enabled: yes 28 | options: [] 29 | -------------------------------------------------------------------------------- /src/test/resources/config-export-expected.yml: -------------------------------------------------------------------------------- 1 | # Test section 2 | test: 3 | # Duration in seconds 4 | duration: 22 5 | # The system name 6 | systemName: Custom sys name 7 | # Sample section 8 | sample: 9 | ratio: 10 | order: FIRST 11 | fields: 12 | - Australia 13 | - Burundi 14 | - Colombia 15 | # The version number 16 | # This is just a random number 17 | version: 2492 18 | features: 19 | # Plain boring features 20 | boring: 21 | # Skip boring features? 22 | skip: false 23 | # Add some boring colors here (gray, beige, ...) 24 | colors: 25 | - beige 26 | - gray 27 | dustLevel: 2.4 28 | 29 | # Cool features 30 | 31 | # Contains cool settings 32 | cool: 33 | # Enable cool features? 34 | enabled: true 35 | # List of cool options to use 36 | options: 37 | - Dinosaurs 38 | - Explosions 39 | - Big trucks 40 | security: 41 | # Forbidden names 42 | forbiddenNames: 43 | - admin 44 | - staff 45 | - moderator -------------------------------------------------------------------------------- /src/test/resources/config-incomplete-sample.yml: -------------------------------------------------------------------------------- 1 | # Test config file with missing options from TestConfiguration 2 | test: 3 | duration: 22 4 | sample: 5 | ratio: 6 | fields: 7 | - 'Australia' 8 | - 'Burundi' 9 | - 'Colombia' 10 | features: 11 | cool: 12 | options: 13 | - 'Dinosaurs' 14 | - 'Explosions' 15 | - 'Big trucks' 16 | -------------------------------------------------------------------------------- /src/test/resources/config-sample.yml: -------------------------------------------------------------------------------- 1 | # Test config file with all options defined in the TestConfiguration class 2 | test: 3 | duration: 22 4 | systemName: 'Custom sys name' 5 | sample: 6 | ratio: 7 | order: 'first' 8 | fields: 9 | - 'Australia' 10 | - 'Burundi' 11 | - 'Colombia' 12 | version: 2492 13 | features: 14 | boring: 15 | skip: false 16 | colors: 17 | - 'beige' 18 | - 'gray' 19 | dustLevel: 2.4 20 | cool: 21 | enabled: true 22 | options: 23 | - 'Dinosaurs' 24 | - 'Explosions' 25 | - 'Big trucks' 26 | security: 27 | forbiddenNames: 28 | - 'ADMIN' 29 | - 'staff' 30 | - 'Moderator' 31 | -------------------------------------------------------------------------------- /src/test/resources/configurationfiles/config-with-chars-to-escape.yml: -------------------------------------------------------------------------------- 1 | shape: 2 | - $ 3 | - $ 4 | - '!' 5 | ingredients: 6 | '!': STICK 7 | $: EMERALD 8 | -------------------------------------------------------------------------------- /src/test/resources/configurationfiles/config-with-number-paths.yml: -------------------------------------------------------------------------------- 1 | tiers: 2 | list: 3 | 1: 4 | level: 1 5 | 2: 6 | level: 2 7 | roles: 8 | 0: 9 | name: 'Initial role' 10 | change-home: false 11 | 1: 12 | name: 'Expert role' 13 | change-home: true 14 | false: 15 | -5: SECOND 16 | -------------------------------------------------------------------------------- /src/test/resources/demo/bean_demo_config.yml: -------------------------------------------------------------------------------- 1 | userdata: 2 | version: 2016.4 3 | bobby: 4 | name: 'Bob' 5 | nicknames: 6 | - 'Bobby' 7 | - 'Bobby boy' 8 | homeLocation: 9 | longitude: 47.3887 10 | latitude: 8.5174 11 | coordinateType: ITRS 12 | richie: 13 | name: 'Richard' 14 | nicknames: 15 | - 'Rich' 16 | homeLocation: 17 | longitude: 47.44 18 | latitude: 8.6 19 | savedLocations: 20 | restaurant: 21 | longitude: 47.5 22 | latitude: 8.7 23 | hospital: 24 | longitude: 47.1 25 | latitude: 8.8901 26 | lionel: 27 | name: 'Lionel' 28 | homeLocation: 29 | longitude: 22.358 30 | latitude: 32.452 31 | coordinateType: ED50 32 | country: 33 | name: 'Sweden' 34 | population: 9593000 35 | neighbors: 36 | - 'Norway' 37 | - 'Finland' 38 | - 'Denmark' 39 | -------------------------------------------------------------------------------- /src/test/resources/demo/config.yml: -------------------------------------------------------------------------------- 1 | title: 2 | text: 'Hello' 3 | size: 11 4 | subtitle: 5 | text: 'Welcome!' 6 | size: 9 7 | color: 'blue' 8 | -------------------------------------------------------------------------------- /src/test/resources/empty_file.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthMe/ConfigMe/36499245ce5f61735445d28d0e1f984c1569fd48/src/test/resources/empty_file.yml -------------------------------------------------------------------------------- /src/test/resources/multiple_lines.yml: -------------------------------------------------------------------------------- 1 | lines: | 2 | First row 3 | 4 | Second row 5 | Third row 6 | -------------------------------------------------------------------------------- /src/test/resources/versions/config-old-version-sample.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | potatoes: 4 3 | tomatoes: 10 4 | --------------------------------------------------------------------------------