001package com.mrivanplays.annotationconfig.toml; 002 003import com.fasterxml.jackson.dataformat.toml.TomlMapper; 004import com.fasterxml.jackson.dataformat.toml.TomlReadFeature; 005import com.mrivanplays.annotationconfig.core.resolver.ConfigResolver; 006import com.mrivanplays.annotationconfig.core.resolver.ValueReader; 007import com.mrivanplays.annotationconfig.core.resolver.ValueWriter; 008import com.mrivanplays.annotationconfig.core.resolver.options.CustomOptions; 009import com.mrivanplays.annotationconfig.core.resolver.options.Option; 010import com.mrivanplays.annotationconfig.core.resolver.settings.LoadSetting; 011import com.mrivanplays.annotationconfig.core.serialization.DataObject; 012import com.mrivanplays.annotationconfig.core.serialization.SerializerRegistry; 013import java.io.File; 014import java.io.IOException; 015import java.io.Reader; 016import java.time.LocalDate; 017import java.time.LocalDateTime; 018import java.time.LocalTime; 019import java.time.OffsetDateTime; 020import java.util.Date; 021import java.util.LinkedHashMap; 022import java.util.Map; 023 024/** 025 * Represents configuration, utilising TOML. 026 * 027 * @since 1.0 028 * @author MrIvanPlays 029 */ 030public final class TomlConfig { 031 032 private static final TomlMapper DEFAULT_TOML_MAPPER = 033 TomlMapper.builder().configure(TomlReadFeature.PARSE_JAVA_TIME, true).build(); 034 035 /** Returns the key on which the mapper is stored. */ 036 public static final String MAPPER_KEY = "mapper"; 037 038 private static ConfigResolver configResolver; 039 040 /** 041 * Returns the {@link ConfigResolver} instance for toml config. 042 * 043 * @return config resolver 044 */ 045 public static ConfigResolver getConfigResolver() { 046 if (configResolver == null) { 047 generateConfigResolver(); 048 } 049 return configResolver; 050 } 051 052 private static final ValueWriter TOML_VALUE_WRITER = new TomlValueWriter(DEFAULT_TOML_MAPPER); 053 054 private static void generateConfigResolver() { 055 configResolver = 056 ConfigResolver.newBuilder() 057 .withOption(MAPPER_KEY, Option.of(DEFAULT_TOML_MAPPER).markReplaceable()) 058 .withLoadSetting(LoadSetting.GENERATE_NEW_OPTIONS, false) 059 .withValueWriter(TOML_VALUE_WRITER) 060 .withCommentPrefix("# ") 061 .shouldReverseFields(true) 062 .withValueReader( 063 new ValueReader() { 064 @Override 065 public Map<String, Object> read(Reader reader, CustomOptions options) 066 throws IOException { 067 return (Map<String, Object>) 068 options 069 .getAsOr(MAPPER_KEY, TomlMapper.class, DEFAULT_TOML_MAPPER) 070 .reader() 071 .readValue(reader, LinkedHashMap.class); 072 } 073 }) 074 .build(); 075 } 076 077 static { 078 SerializerRegistry registry = SerializerRegistry.INSTANCE; 079 if (!registry.hasSerializer(Date.class)) { 080 registry.registerSerializer(Date.class, new DateResolver()); 081 } 082 if (!registry.hasSerializer(OffsetDateTime.class)) { 083 registry.registerSerializer( 084 OffsetDateTime.class, 085 (data, field) -> OffsetDateTime.parse(data.getAsString()), 086 (value, field) -> new DataObject(value.toString())); 087 } 088 if (!registry.hasSerializer(LocalDateTime.class)) { 089 registry.registerSerializer( 090 LocalDateTime.class, 091 (data, field) -> LocalDateTime.parse(data.getAsString()), 092 (value, field) -> new DataObject(value.toString())); 093 } 094 if (!registry.hasSerializer(LocalDate.class)) { 095 registry.registerSerializer( 096 LocalDate.class, 097 (data, field) -> LocalDate.parse(data.getAsString()), 098 (value, field) -> new DataObject(value.toString())); 099 } 100 if (!registry.hasSerializer(LocalTime.class)) { 101 registry.registerSerializer( 102 LocalTime.class, 103 (data, field) -> LocalTime.parse(data.getAsString()), 104 (value, field) -> new DataObject(value.toString())); 105 } 106 } 107 108 /** 109 * Loads the config object from the file. If the file does not exist, it creates one. 110 * 111 * @param annotatedConfig annotated config 112 * @param file file 113 * @deprecated see {@link #load(Object, File, TomlMapper)} 114 */ 115 @Deprecated 116 public static void load(Object annotatedConfig, File file) { 117 load(annotatedConfig, file, DEFAULT_TOML_MAPPER); 118 } 119 120 /** 121 * Loads the config object from the file. If the file does not exist, it creates one. 122 * 123 * @param annotatedConfig annotated config 124 * @param file file 125 * @param tomlMapper toml mapper 126 * @deprecated use {@link #getConfigResolver()} 127 */ 128 @Deprecated 129 public static void load(Object annotatedConfig, File file, TomlMapper tomlMapper) { 130 ConfigResolver resolver = getConfigResolver(); 131 if (!resolver.options().has(MAPPER_KEY)) { 132 resolver.options().put(MAPPER_KEY, Option.of(tomlMapper).markReplaceable()); 133 } else { 134 if (resolver.options().isReplaceable(MAPPER_KEY).orElse(false)) { 135 resolver.options().put(MAPPER_KEY, Option.of(tomlMapper).markReplaceable()); 136 } 137 } 138 resolver.loadOrDump(annotatedConfig, file); 139 } 140}