├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
└── xyz
└── mkotb
└── configapi
├── Coloured.java
├── ConfigFactory.java
├── RequiredField.java
├── comment
├── Comment.java
├── CommentHelper.java
├── Comments.java
├── HeaderComment.java
├── HeaderComments.java
└── Self.java
├── ex
├── ClassStructureException.java
├── InternalProcessingException.java
└── InvalidConfigurationException.java
└── internal
├── InternalsHelper.java
├── SerializableMemorySection.java
├── adapt
├── AdapterHandler.java
├── ObjectAdapter.java
└── impl
│ ├── ArrayAdapter.java
│ ├── CollectionAdapter.java
│ ├── DateAdapter.java
│ ├── MapAdapter.java
│ ├── SQLDateAdapter.java
│ ├── UUIDAdapter.java
│ ├── atomic
│ ├── AtomicBooleanAdapter.java
│ ├── AtomicIntegerAdapter.java
│ ├── AtomicIntegerArrayAdapter.java
│ ├── AtomicLongAdapter.java
│ └── AtomicLongArrayAdapter.java
│ └── bukkit
│ ├── ConfigurationSectionAdapter.java
│ ├── ConfigurationSerializableHelper.java
│ ├── EnchantmentAdapter.java
│ └── OfflinePlayerAdapter.java
├── dummy
└── CentralDummyHolder.java
└── naming
├── CamelCaseNamingStrategy.java
├── DummyNamingStrategy.java
├── NamingStrategies.java
├── NamingStrategy.java
└── UnderscoreNamingStrategy.java
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
2 |
3 | Permission to use, copy, modify, and/or distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ConfigAPI
2 | This project is a GSON-like project for Bukkit's YML Config API. This project is on maven central! You can add it to your project using the following:
3 |
4 | ```xml
5 |
6 | xyz.mkotb
7 | config-api
8 | 1.0.1
9 |
10 | ```
11 |
12 | If you're not familiar with GSON, let me show you a quick example of what you can do with this API:
13 |
14 | ```java
15 | public class MyPlugin extends JavaPlugin {
16 | private MyConfig myConfig;
17 | private ConfigFactory configFactory = ConfigFactory.newFactory(this);
18 |
19 | @Override
20 | public void onEnable() {
21 | myConfig = configFactory.fromFile("config", MyConfig.class);
22 | getLogger().info(myConfig.getStartMessage());
23 |
24 | if (myConfig.myFavouriteNumbers != null) {
25 | getLogger().info(myConfig.myFavouriteNumbers.toString());
26 | }
27 | }
28 |
29 | @Override
30 | public void onDisable() {
31 | // if we changed values in my config while the server is up
32 | // we should save it
33 | configFactory.save("config", myConfig);
34 | }
35 | }
36 |
37 | @Comment("This is my header comment")
38 | public class MyConfig {
39 | // init values will be saved as part of the "default config"
40 | private String startMessage = "This awesome bukkit plugin has started!";
41 | @Comment("Put in your favourite number here!")
42 | @RequiredField // if this field is not set in the config file due to user error
43 | // an exception will be thrown
44 | private int myFavouriteNumber = 3;
45 | // lists, sets, queues, maps, and arrays are supported!
46 | List myFavouriteNumbers;
47 | // supports concurrency classes!
48 | private AtomicInteger myFavouriteAtomicNumber = new AtomicInteger(4);
49 | // myWeapon will be set if it's in the config but won't exist
50 | // by default
51 | private ItemStack myWeapon;
52 | // additionally objects within the config are allowed
53 | private PartOfConfig part;
54 |
55 | public String getStartMessage() {
56 | return startMessage;
57 | }
58 | }
59 |
60 | public class PartOfConfig {
61 | private String hi = "my name is billy";
62 | }
63 | ```
64 |
65 | In the following example, we displayed majority of the features available in the API. The `fromFile()` method takes care of all the initial processes you may need, such as creating the new file and placing default values. Many additional classes such as color, offline players, and vectors are supported to be saved. In the future, extensibility to the Adapter API will be added to where you can use your own data types which can be converted.
66 |
67 | ## Interaction with the File
68 |
69 | As of currently, if you were to setup and run this plugin, it would write the following to `config.yml` using the default values:
70 |
71 | ```yml
72 | # This is my header comment
73 | start-message: This awesome bukkit plugin has started!
74 | # Put in your favourite number here!
75 | my-favourite-number: 3
76 | my-favourite-atomic-number: 4
77 | ```
78 |
79 | As you can see, it only saved the fields which were already set as defaults. If you haven't noticed already, the API changed the naming conventions from Java lower camel case (`likeThis`) to the conventional YAML namespace (`like-this`). You can modify which naming convention the API uses. There will be more information you can refer to on this on [the wiki]( Wiki).
80 |
81 | If we were to add a list of our favourite numbers to the config manually, we will be able to see the API being able to load them up without a problem:
82 |
83 | ```yml
84 | my-favourite-numbers:
85 | - 2
86 | - 6
87 | - 8
88 | ```
89 |
90 | And if we start up our server with the new config, we'll see the following printed in console:
91 |
92 | ```
93 | [01:09:42 INFO]: [ConfigTestPlugin] Enabling ConfigTestPlugin v1.0
94 | [01:09:42 INFO]: [ConfigTestPlugin] This super cool awesome bukkit plugin has started!
95 | [01:09:42 INFO]: [ConfigTestPlugin] [2, 6, 8]
96 | ```
97 |
98 | Well, that was easy.
99 |
100 | ConfigAPI is still in early development and will soon be for release for developers to use in their projects. Contributions are more than welcome!
101 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | xyz.mkotb
8 | config-api
9 | 1.0.1
10 |
11 | ConfigAPI
12 | GSON-like ORM for the Bukkit Config API
13 | http://github.com/mkotb/ConfigAPI
14 |
15 |
16 | UTF-8
17 |
18 |
19 |
20 | scm:git:git@github.com:mkotb/ConfigAPI.git
21 | scm:git:git@github.com:mkotb/ConfigAPI.git
22 | git@github.com:mkotb/ConfigAPI.git
23 |
24 |
25 |
26 |
27 | ISC License
28 | http://choosealicense.com/licenses/isc/
29 |
30 |
31 |
32 |
33 |
34 | spigot-repo
35 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/
36 |
37 |
38 |
39 |
40 |
41 | ossrh
42 | https://oss.sonatype.org/content/repositories/snapshots
43 |
44 |
45 | ossrh
46 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
47 |
48 |
49 |
50 |
51 |
52 | mkotb
53 | Mazen Kotb
54 | mazenkotb@gmail.com
55 | PST
56 | https://github.com/mkotb
57 |
58 |
59 |
60 |
61 |
62 |
63 | org.spigotmc
64 | spigot-api
65 | 1.10.2-R0.1-SNAPSHOT
66 | provided
67 |
68 |
69 |
70 |
71 | org.bukkit
72 | bukkit
73 | 1.10.2-R0.1-SNAPSHOT
74 | provided
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-shade-plugin
84 | 2.4.3
85 |
86 |
87 | package
88 |
89 | shade
90 |
91 |
92 |
93 |
94 |
95 | org.apache.maven.plugins
96 | maven-compiler-plugin
97 | 3.3
98 |
99 | 1.8
100 | 1.8
101 | true
102 | true
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | org.apache.maven.plugins
111 | maven-jar-plugin
112 | 2.4
113 |
114 |
115 |
116 | com.mycila.maven-license-plugin
117 | maven-license-plugin
118 |
119 |
120 |
121 | true
122 | UTF-8
123 | true
124 |
125 |
126 | SLASHSTAR_STYLE
127 |
128 |
129 | license
130 |
131 |
132 | src/main/java/**
133 | src/test/java/**
134 |
135 |
136 | clean
137 |
138 | format
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | ossrh
149 |
150 |
151 |
152 | maven-gpg-plugin
153 | 1.6
154 |
155 |
156 | sign-artifacts
157 | verify
158 |
159 | sign
160 |
161 |
162 |
163 |
164 | true
165 |
166 |
167 |
168 | org.apache.maven.plugins
169 | maven-source-plugin
170 | 2.4
171 |
172 |
173 | attach-sources
174 |
175 | jar-no-fork
176 |
177 |
178 |
179 |
180 |
181 | org.apache.maven.plugins
182 | maven-javadoc-plugin
183 | 2.10.3
184 |
185 |
186 | attach-javadocs
187 |
188 | jar
189 |
190 |
191 |
192 |
193 |
194 | org.sonatype.plugins
195 | nexus-staging-maven-plugin
196 | 1.6.6
197 | true
198 |
199 | ossrh
200 | https://oss.sonatype.org/
201 | true
202 |
203 |
204 |
205 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/Coloured.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.FIELD)
25 | public @interface Coloured {
26 | char value() default '&';
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/ConfigFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi;
17 |
18 | import org.bukkit.ChatColor;
19 | import org.bukkit.configuration.MemorySection;
20 | import org.bukkit.configuration.file.FileConfiguration;
21 | import org.bukkit.configuration.file.YamlConfiguration;
22 | import org.bukkit.plugin.java.JavaPlugin;
23 | import xyz.mkotb.configapi.comment.CommentHelper;
24 | import xyz.mkotb.configapi.ex.ClassStructureException;
25 | import xyz.mkotb.configapi.ex.InternalProcessingException;
26 | import xyz.mkotb.configapi.internal.InternalsHelper;
27 | import xyz.mkotb.configapi.internal.SerializableMemorySection;
28 | import xyz.mkotb.configapi.internal.adapt.AdapterHandler;
29 | import xyz.mkotb.configapi.internal.dummy.CentralDummyHolder;
30 | import xyz.mkotb.configapi.internal.naming.CamelCaseNamingStrategy;
31 | import xyz.mkotb.configapi.internal.naming.NamingStrategy;
32 |
33 | import java.io.File;
34 | import java.io.IOException;
35 | import java.io.PrintWriter;
36 | import java.lang.reflect.Field;
37 | import java.util.Map;
38 |
39 | public final class ConfigFactory {
40 | private volatile NamingStrategy namingStrategy = new CamelCaseNamingStrategy();
41 | private final JavaPlugin plugin;
42 |
43 | private ConfigFactory(JavaPlugin plugin) {
44 | this.plugin = plugin;
45 | File directory = plugin.getDataFolder();
46 |
47 | if (directory.exists()) {
48 | directory.mkdirs();
49 | }
50 | }
51 |
52 | public static ConfigFactory newFactory(JavaPlugin plugin) {
53 | return new ConfigFactory(plugin);
54 | }
55 |
56 | public T fromFile(String name, Class classOf) {
57 | return fromFile(new File(configDirectory(), name + ".yml"), classOf);
58 | }
59 |
60 | public T fromFile(File config, Class classOf) {
61 | if (!config.exists()) {
62 | CentralDummyHolder dummyHolder = CentralDummyHolder.instance();
63 | T dummy;
64 |
65 | if ((dummy = dummyHolder.dummyFrom(classOf)) == null) {
66 | dummy = InternalsHelper.newInstance(classOf);
67 |
68 | if (dummy == null) {
69 | throw new ClassStructureException("An accessible no-args constructor could not " +
70 | "be found in " + classOf.getName());
71 | }
72 | }
73 |
74 | colourizeFields(dummy);
75 | save(config, dummy);
76 | dummyHolder.insertDummy(classOf, dummy);
77 | return dummy;
78 | }
79 |
80 | AdapterHandler handler = AdapterHandler.create(namingStrategy);
81 | FileConfiguration data = YamlConfiguration.loadConfiguration(config);
82 | return colourizeFields(handler.adaptIn(data, null, classOf));
83 | }
84 |
85 | public void save(String name, T object) {
86 | save(new File(configDirectory(), name + ".yml"), object);
87 | }
88 |
89 | public void save(File config, T object) {
90 | if (!config.exists()) {
91 | try {
92 | config.getParentFile().mkdirs();
93 | config.createNewFile();
94 | } catch (IOException ex) {
95 | throw new InternalProcessingException("Could not create file!", ex);
96 | }
97 | }
98 |
99 | StringBuilder sb = new StringBuilder();
100 | Map comments = CommentHelper.extractComments(object, namingStrategy);
101 | String[] header = CommentHelper.extractHeader(object.getClass());
102 | AdapterHandler handler = AdapterHandler.create(namingStrategy);
103 | MemorySection section = handler.adaptOut(object, MemorySection.class);
104 |
105 | if (header != null) {
106 | CommentHelper.encodeComments(header, sb);
107 | }
108 |
109 | ((SerializableMemorySection) section).map().forEach((k, v) -> {
110 | FileConfiguration fieldData = new YamlConfiguration();
111 |
112 | if (comments.containsKey(k)) {
113 | CommentHelper.encodeComments(comments.get(k), sb);
114 | }
115 |
116 | fieldData.set(k, v);
117 | sb.append(fieldData.saveToString());
118 | });
119 |
120 | try (PrintWriter out = new PrintWriter(config)){
121 | out.print(sb.toString());
122 | } catch (IOException ex) {
123 | throw new InternalProcessingException("Unable to save config to file!", ex);
124 | }
125 | }
126 |
127 | private T colourizeFields(T object) {
128 | for (Field field : object.getClass().getDeclaredFields()) {
129 | if (!field.isAnnotationPresent(Coloured.class)) {
130 | continue;
131 | }
132 |
133 | if (field.getType() != String.class) {
134 | continue;
135 | }
136 |
137 | Coloured annotation = field.getDeclaredAnnotation(Coloured.class);
138 | String value = InternalsHelper.getField(field, object);
139 |
140 | if (value != null) {
141 | InternalsHelper.setField(field, object, AdapterHandler.translateAlternateColorCodes(
142 | ChatColor.COLOR_CHAR, annotation.value(), value));
143 | }
144 | }
145 |
146 | return object;
147 | }
148 |
149 | private File configDirectory() {
150 | return plugin.getDataFolder();
151 | }
152 |
153 | public NamingStrategy namingStrategy() {
154 | return namingStrategy;
155 | }
156 |
157 | public void setPreferredStrategy(NamingStrategy preferredStrategy) {
158 | this.namingStrategy = preferredStrategy;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/RequiredField.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(value = RetentionPolicy.RUNTIME)
24 | @Target(value = ElementType.FIELD)
25 | public @interface RequiredField {
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/Comment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target({ElementType.FIELD, ElementType.TYPE})
25 | public @interface Comment {
26 | String[] value();
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/CommentHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import xyz.mkotb.configapi.internal.naming.NamingStrategy;
19 |
20 | import java.lang.annotation.Annotation;
21 | import java.lang.reflect.Field;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | public final class CommentHelper {
26 | private CommentHelper() {
27 | }
28 |
29 | public static void encodeComments(String[] comments, StringBuilder builder) {
30 | for (String comment : comments) {
31 | builder.append("# ").append(comment).append(System.lineSeparator());
32 | }
33 | }
34 |
35 | public static Map extractComments(Object object, NamingStrategy namingStrat) {
36 | Map comments = new HashMap<>();
37 |
38 | for(Field field : object.getClass().getDeclaredFields()) {
39 | for (Annotation annotation : field.getDeclaredAnnotations()) {
40 | String[] value = valueFrom(annotation);
41 |
42 | if (value != null) {
43 | comments.put(namingStrat.rename(field.getName()), value);
44 | break;
45 | }
46 | }
47 | }
48 |
49 | return comments;
50 | }
51 |
52 | public static String[] extractHeader(Class> cls) {
53 | for (Annotation annotation : cls.getAnnotations()) {
54 | String[] value = valueFrom(annotation);
55 |
56 | if (value != null) {
57 | return value;
58 | }
59 | }
60 |
61 | return null;
62 | }
63 |
64 | public static String[] valueFrom(Annotation annotation) {
65 | if (annotation instanceof Comment) {
66 | return ((Comment) annotation).value();
67 | }
68 |
69 | if (annotation instanceof HeaderComment) {
70 | return new String[] {((HeaderComment) annotation).value()};
71 | }
72 |
73 | if (annotation instanceof Comments) {
74 | return ((Comments) annotation).value();
75 | }
76 |
77 | if (annotation instanceof HeaderComments) {
78 | return ((HeaderComments) annotation).value();
79 | }
80 |
81 | return null;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/Comments.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.FIELD)
25 | @Deprecated
26 | public @interface Comments {
27 | String[] value();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/HeaderComment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.TYPE)
25 | @Deprecated
26 | public @interface HeaderComment {
27 | String value();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/HeaderComments.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.TYPE)
25 | @Deprecated
26 | public @interface HeaderComments {
27 | String[] value();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/comment/Self.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.comment;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Target(ElementType.FIELD)
25 | public @interface Self {
26 | String value() default "";
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/ex/ClassStructureException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.ex;
17 |
18 | public class ClassStructureException extends RuntimeException {
19 | public ClassStructureException() {
20 | }
21 |
22 | public ClassStructureException(String message) {
23 | super(message);
24 | }
25 |
26 | public ClassStructureException(String message, Throwable cause) {
27 | super(message, cause);
28 | }
29 |
30 | public ClassStructureException(Throwable cause) {
31 | super(cause);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/ex/InternalProcessingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.ex;
17 |
18 | public class InternalProcessingException extends RuntimeException {
19 | public InternalProcessingException() {
20 | }
21 |
22 | public InternalProcessingException(String message) {
23 | super(message);
24 | }
25 |
26 | public InternalProcessingException(String message, Throwable cause) {
27 | super(message, cause);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/ex/InvalidConfigurationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.ex;
17 |
18 | public class InvalidConfigurationException extends RuntimeException {
19 | public InvalidConfigurationException() {
20 | }
21 |
22 | public InvalidConfigurationException(String message) {
23 | super(message);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/internal/InternalsHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.internal;
17 |
18 | import sun.reflect.ReflectionFactory;
19 | import xyz.mkotb.configapi.internal.naming.NamingStrategies;
20 | import xyz.mkotb.configapi.internal.naming.NamingStrategy;
21 |
22 | import java.lang.reflect.Constructor;
23 | import java.lang.reflect.Field;
24 | import java.lang.reflect.ParameterizedType;
25 | import java.lang.reflect.Type;
26 | import java.util.HashMap;
27 | import java.util.Map;
28 | import java.util.concurrent.ConcurrentHashMap;
29 |
30 | public final class InternalsHelper {
31 | private static final Map FIELD_CACHE = new ConcurrentHashMap<>();
32 |
33 | private InternalsHelper() {
34 | }
35 |
36 | public static Class typeOf(Field field, int index) {
37 | Type genericType = field.getGenericType();
38 |
39 | if (genericType instanceof ParameterizedType) {
40 | return (Class) ((ParameterizedType) genericType).getActualTypeArguments()[index];
41 | }
42 |
43 | return Object.class;
44 | }
45 |
46 | /*
47 | * Creates an instance of the class without calling it's constructor.
48 | * clazz must implement java.io.Serializable
49 | */
50 | public static T newInstanceWithoutInit(Class clazz) {
51 | try {
52 | ReflectionFactory rf =
53 | ReflectionFactory.getReflectionFactory();
54 | Constructor objDef = Object.class.getDeclaredConstructor();
55 | Constructor intConstr = rf.newConstructorForSerialization(clazz, objDef);
56 |
57 | return clazz.cast(intConstr.newInstance());
58 | } catch (RuntimeException e) {
59 | throw e;
60 | } catch (Exception e) {
61 | throw new IllegalStateException("Cannot create object", e);
62 | }
63 | }
64 |
65 | public static T newInstance(Class classOf) {
66 | try {
67 | return classOf.newInstance();
68 | } catch (InstantiationException | IllegalAccessException ex) {
69 | return null;
70 | }
71 | }
72 |
73 | public static Map mapFieldsOf(T obj) {
74 | return mapFieldsOf(obj, NamingStrategies.from("dummy"));
75 | }
76 |
77 | public static Map mapFieldsOf(T obj, NamingStrategy strategy) {
78 | Map fieldMap = new HashMap<>();
79 | Field[] fields = obj.getClass().getFields();
80 |
81 | for (Field field : fields) {
82 | fieldMap.put(strategy.rename(field.getName()), getField(field, obj));
83 | }
84 |
85 | return fieldMap;
86 | }
87 |
88 | public static Field staticFieldFor(Class> clazz, String name) {
89 | try {
90 | String id = fieldIdentifier(clazz, name);
91 |
92 | if (FIELD_CACHE.containsKey(id)) {
93 | return FIELD_CACHE.get(id);
94 | }
95 |
96 | Field field = clazz.getDeclaredField(name);
97 |
98 | FIELD_CACHE.put(id, field);
99 | return field;
100 | } catch (NoSuchFieldException ex) {
101 | return null;
102 | }
103 | }
104 |
105 | public static Field fieldFor(Object object, String name) {
106 | try {
107 | String id = fieldIdentifier(object.getClass(), name);
108 |
109 | if (FIELD_CACHE.containsKey(id)) {
110 | return FIELD_CACHE.get(id);
111 | }
112 | Field field = object.getClass().getDeclaredField(name);
113 |
114 | FIELD_CACHE.put(id, field);
115 | return field;
116 | } catch (NoSuchFieldException ignored) {
117 | return null;
118 | }
119 | }
120 |
121 | public static T getField(Field field, Object instance) {
122 | try {
123 | field.setAccessible(true);
124 | return (T) field.get(instance);
125 | } catch (IllegalAccessException ex) {
126 | return null;
127 | }
128 | }
129 |
130 | public static boolean setField(String fieldName, Object instance, Object value) {
131 | Field field = fieldFor(instance, fieldName);
132 | return field != null && setField(field, instance, value);
133 | }
134 |
135 | public static boolean setField(Field field, Object instance, Object value) {
136 | try {
137 | field.setAccessible(true);
138 | field.set(instance, value);
139 | return true;
140 | } catch (IllegalAccessException ex) {
141 | return false;
142 | }
143 | }
144 |
145 | private static String fieldIdentifier(Class> cls, String fieldName) {
146 | return cls.getName() + "||" + fieldName;
147 | }
148 |
149 | private static String fieldIdentifier(Field field) {
150 | return field.getDeclaringClass().getName() + "||" + field.getName();
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/internal/SerializableMemorySection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.internal;
17 |
18 | import org.bukkit.configuration.MemorySection;
19 |
20 | import java.io.Serializable;
21 | import java.util.LinkedHashMap;
22 | import java.util.Map;
23 | import java.util.Set;
24 |
25 | public class SerializableMemorySection extends MemorySection implements Serializable {
26 | private Map map;
27 |
28 | @Override
29 | public Object get(String path, Object def) {
30 | Object value = map().get(path);
31 | return value == null ? def : value;
32 | }
33 |
34 | @Override
35 | public void set(String path, Object value) {
36 | map().put(path, value);
37 | }
38 |
39 | @Override
40 | public Set getKeys(boolean deep) {
41 | return map().keySet();
42 | }
43 |
44 | @Override
45 | public Map getValues(boolean deep) {
46 | return map();
47 | }
48 |
49 | @Override
50 | protected Object getDefault(String path) {
51 | return null;
52 | }
53 |
54 | public Map map() {
55 | if (map == null) {
56 | map = new LinkedHashMap<>();
57 | }
58 |
59 | return map;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/internal/adapt/AdapterHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.internal.adapt;
17 |
18 | import org.bukkit.ChatColor;
19 | import org.bukkit.OfflinePlayer;
20 | import org.bukkit.enchantment.Enchantment;
21 | import org.bukkit.configuration.ConfigurationSection;
22 | import org.bukkit.configuration.MemorySection;
23 | import org.bukkit.configuration.serialization.ConfigurationSerializable;
24 | import xyz.mkotb.configapi.Coloured;
25 | import xyz.mkotb.configapi.RequiredField;
26 | import xyz.mkotb.configapi.comment.Self;
27 | import xyz.mkotb.configapi.ex.ClassStructureException;
28 | import xyz.mkotb.configapi.ex.InvalidConfigurationException;
29 | import xyz.mkotb.configapi.internal.InternalsHelper;
30 | import xyz.mkotb.configapi.internal.SerializableMemorySection;
31 | import xyz.mkotb.configapi.internal.adapt.impl.*;
32 | import xyz.mkotb.configapi.internal.adapt.impl.atomic.*;
33 | import xyz.mkotb.configapi.internal.adapt.impl.bukkit.*;
34 | import xyz.mkotb.configapi.internal.naming.NamingStrategy;
35 |
36 | import java.lang.reflect.Field;
37 | import java.lang.reflect.Modifier;
38 | import java.util.*;
39 | import java.util.concurrent.ConcurrentHashMap;
40 | import java.util.concurrent.atomic.*;
41 |
42 | public final class AdapterHandler {
43 | private static final Map, Class>> PRIMITIVE_BOXES = new ConcurrentHashMap<>();
44 | private static final Set> FILTER_CLASSES = new HashSet<>();
45 | private static final Map, ObjectAdapter, ?>> ADAPTERS = new ConcurrentHashMap<>();
46 |
47 | static {
48 | PRIMITIVE_BOXES.put(boolean.class, Boolean.class);
49 | PRIMITIVE_BOXES.put(char.class, Character.class);
50 | PRIMITIVE_BOXES.put(byte.class, Byte.class);
51 | PRIMITIVE_BOXES.put(short.class, Short.class);
52 | PRIMITIVE_BOXES.put(int.class, Integer.class);
53 | PRIMITIVE_BOXES.put(long.class, Long.class);
54 | PRIMITIVE_BOXES.put(float.class, Float.class);
55 | PRIMITIVE_BOXES.put(double.class, Double.class);
56 | PRIMITIVE_BOXES.put(void.class, Void.class);
57 |
58 | ADAPTERS.put(Date.class, new DateAdapter());
59 | ADAPTERS.put(java.sql.Date.class, new SQLDateAdapter());
60 | ADAPTERS.put(UUID.class, new UUIDAdapter());
61 |
62 | ADAPTERS.put(ConfigurationSection.class, new ConfigurationSectionAdapter());
63 | ADAPTERS.put(Enchantment.class, new EnchantmentAdapter());
64 | ADAPTERS.put(OfflinePlayer.class, new OfflinePlayerAdapter());
65 |
66 | ADAPTERS.put(AtomicBoolean.class, new AtomicBooleanAdapter());
67 | ADAPTERS.put(AtomicInteger.class, new AtomicIntegerAdapter());
68 | ADAPTERS.put(AtomicIntegerArray.class, new AtomicIntegerArrayAdapter());
69 | ADAPTERS.put(AtomicLong.class, new AtomicLongAdapter());
70 | ADAPTERS.put(AtomicLongArray.class, new AtomicLongArrayAdapter());
71 |
72 | FILTER_CLASSES.addAll(ADAPTERS.keySet());
73 | FILTER_CLASSES.addAll(PRIMITIVE_BOXES.values());
74 | FILTER_CLASSES.add(String.class);
75 | FILTER_CLASSES.add(Map.class);
76 | FILTER_CLASSES.add(Collection.class);
77 | }
78 |
79 | private final NamingStrategy namingStrategy;
80 |
81 | private AdapterHandler(NamingStrategy strategy) {
82 | this.namingStrategy = strategy;
83 | }
84 |
85 | public static AdapterHandler create(NamingStrategy strategy) {
86 | return new AdapterHandler(strategy);
87 | }
88 |
89 | public static void registerAdapter(Class clazz, ObjectAdapter adapter) {
90 | ADAPTERS.replace(clazz, adapter);
91 | }
92 |
93 | public static boolean isSerializable(Class> clazz) {
94 | return (ConfigurationSerializable.class.isAssignableFrom(clazz) &&
95 | ConfigurationSerializableHelper.isRegistered(clazz)) ||
96 | ((FILTER_CLASSES.stream().anyMatch((e) -> e.isAssignableFrom(clazz) || clazz.equals(e))));
97 | }
98 |
99 | public static Class> outClass(Class> clazz) {
100 | if (!isSerializable(clazz)) {
101 | return MemorySection.class;
102 | }
103 |
104 | return clazz;
105 | }
106 |
107 | public O adaptOut(I input, Class outClass) {
108 | return adaptOut(input, outClass, null);
109 | }
110 |
111 | public O adaptOut(I input, Class outClass, Class> type) {
112 | if (Collection.class.isAssignableFrom(input.getClass())) {
113 | CollectionAdapter adapter = CollectionAdapter.create(type,
114 | (Class extends Collection>) outClass, this);
115 | return outClass.cast(adapter.write((Collection) input));
116 | }
117 |
118 | if (Map.class.isAssignableFrom(input.getClass())) {
119 | MapAdapter adapter = MapAdapter.create(type,
120 | this);
121 | return outClass.cast(adapter.write((Map) input));
122 | }
123 |
124 | if (input.getClass().isArray()) {
125 | Class> cls = input.getClass();
126 | ArrayAdapter adapter = ArrayAdapter.create(cls.getComponentType(), this);
127 | return outClass.cast(adapter.write(input));
128 | }
129 |
130 | if (PRIMITIVE_BOXES.values().contains(outClass) || input.getClass().isPrimitive()) {
131 | return outClass.cast(input);
132 | }
133 |
134 | if (outClass == String.class) {
135 | return outClass.cast(input);
136 | }
137 |
138 | ObjectAdapter, ?> oldAdapter = ADAPTERS.get(input.getClass());
139 |
140 | if (oldAdapter == null) {
141 | if (ConfigurationSerializableHelper.isRegistered(input.getClass()) && // ensure registration for deserialization purposes
142 | input instanceof ConfigurationSerializable) {
143 | MemorySection memorySection = InternalsHelper.newInstanceWithoutInit(SerializableMemorySection.class);
144 | ((ConfigurationSerializable) input).serialize().forEach(memorySection::set);
145 | return outClass.cast(memorySection);
146 | }
147 |
148 | MemorySection section = InternalsHelper.newInstanceWithoutInit(SerializableMemorySection.class);
149 | InternalsHelper.setField("map", section, new LinkedHashMap());
150 | Field[] fields = input.getClass().getDeclaredFields();
151 | Field selfField = null;
152 |
153 | for (Field field : fields) {
154 | if (Modifier.isTransient(field.getModifiers())) {
155 | continue;
156 | }
157 |
158 | Object value = InternalsHelper.getField(field, input);
159 |
160 | if (value != null) {
161 | Class> fieldType = null;
162 | Class> fieldClass = field.getType();
163 | Class> beforeFieldClass = fieldClass;
164 |
165 | if (field.getDeclaredAnnotation(Self.class) != null) {
166 | if (!ConfigurationSection.class.isAssignableFrom(beforeFieldClass)) {
167 | throw new ClassStructureException("Field " + field.getName() + " with @Self annotation is not a " +
168 | "configuration section, is " + beforeFieldClass.getName());
169 | }
170 |
171 | selfField = field;
172 | continue;
173 | }
174 |
175 | if (!FILTER_CLASSES.stream().anyMatch((e) -> e.isAssignableFrom(beforeFieldClass))
176 | && !fieldClass.isArray()) {
177 | fieldClass = MemorySection.class;
178 | }
179 |
180 | if (beforeFieldClass.isPrimitive()) {
181 | fieldClass = PRIMITIVE_BOXES.get(beforeFieldClass);
182 | }
183 |
184 | if (Map.class.isAssignableFrom(fieldClass)) {
185 | fieldType = InternalsHelper.typeOf(field, 1);
186 | fieldClass = ConfigurationSection.class;
187 | } else if (Collection.class.isAssignableFrom(fieldClass)) {
188 | fieldType = InternalsHelper.typeOf(field, 0);
189 | fieldClass = Object.class;
190 | } else if (fieldClass.isArray()) {
191 | fieldClass = Object.class;
192 | }
193 |
194 | Object obj = adaptOut(value, fieldClass, fieldType);
195 |
196 | if (obj instanceof String && field.isAnnotationPresent(Coloured.class)) {
197 | Coloured annotation = field.getDeclaredAnnotation(Coloured.class);
198 | obj = translateAlternateColorCodes(annotation.value(), ChatColor.COLOR_CHAR, (String) obj);
199 | }
200 |
201 | section.set(namingStrategy.rename(field.getName()), obj);
202 | }
203 | }
204 |
205 | if (selfField != null) {
206 | ConfigurationSection selfSec = InternalsHelper.getField(selfField, input);
207 |
208 | if (selfSec != null) {
209 | selfSec.getValues(false).forEach((key, value) -> {
210 | if (!section.contains(key)) {
211 | section.set(key, value);
212 | }
213 | });
214 | }
215 | }
216 |
217 | return outClass.cast(section);
218 | }
219 |
220 | ObjectAdapter adapter;
221 |
222 | try {
223 | adapter = (ObjectAdapter) oldAdapter;
224 | } catch (ClassCastException ex) {
225 | throw new ClassStructureException(outClass.getName() + " does not match registered adapter" +
226 | " for " + input.getClass().getName() + "!");
227 | }
228 |
229 | return adapter.write(input);
230 | }
231 |
232 | public I adaptIn(ConfigurationSection section, String key, Class inClass) {
233 | return adaptIn(section, key, inClass, null);
234 | }
235 |
236 | public I adaptIn(ConfigurationSection section, String key, Class inClass, Class> type) {
237 | if (inClass.isArray()) {
238 | ArrayAdapter adapter = ArrayAdapter.create(inClass.getComponentType(), this);
239 | return inClass.cast(adapter.read(key, section));
240 | }
241 |
242 | if (Collection.class.isAssignableFrom(inClass)) {
243 | CollectionAdapter adapter = CollectionAdapter.create(type,
244 | (Class extends Collection>) inClass, this);
245 | return inClass.cast(adapter.read(key, section));
246 | }
247 |
248 | if (Map.class.isAssignableFrom(inClass)) {
249 | MapAdapter adapter = MapAdapter.create(type,
250 | this);
251 | return inClass.cast(adapter.read(key, section));
252 | }
253 |
254 | if (inClass.isPrimitive() || inClass == String.class || PRIMITIVE_BOXES.values().contains(inClass)) {
255 | return inClass.cast(section.get(key));
256 | }
257 |
258 | ObjectAdapter, ?> oldAdapter = ADAPTERS.get(inClass);
259 |
260 | if (oldAdapter == null) {
261 | if (ConfigurationSerializableHelper.isRegistered(inClass) &&
262 | ConfigurationSerializable.class.isAssignableFrom(inClass)) {
263 | return ConfigurationSerializableHelper.deserialize(ConfigurationSerializableHelper.toMap(section.getConfigurationSection(key)),
264 | inClass);
265 | }
266 |
267 | ConfigurationSection readingSection = (key == null) ? section : section.getConfigurationSection(key);
268 | I instance = InternalsHelper.newInstance(inClass);
269 | Field[] fields = inClass.getDeclaredFields();
270 | Field selfField = null;
271 |
272 | for (Field field : fields) {
273 | if (Modifier.isTransient(field.getModifiers())) {
274 | continue;
275 | }
276 |
277 | String name = namingStrategy.rename(field.getName());
278 |
279 | if (field.getDeclaredAnnotation(Self.class) != null) {
280 | if (!ConfigurationSection.class.isAssignableFrom(field.getType())) {
281 | throw new ClassStructureException("Field " + field.getName() + " with @Self annotation is not a " +
282 | "configuration section, is " + field.getType().getName());
283 | }
284 |
285 | selfField = field;
286 | continue;
287 | }
288 |
289 | if (!readingSection.contains(name)) {
290 | if (field.getAnnotation(RequiredField.class) != null) {
291 | String message = "Could not find the required field, " + name;
292 |
293 | if (key != null) {
294 | message += ", in section " + key;
295 | }
296 |
297 | throw new InvalidConfigurationException(message);
298 | }
299 |
300 | continue;
301 | }
302 |
303 | Class> fieldType = null;
304 | Class> fieldClass = field.getType();
305 |
306 | if (fieldClass.isPrimitive()) {
307 | fieldClass = PRIMITIVE_BOXES.get(fieldClass);
308 | }
309 |
310 | if (Map.class.isAssignableFrom(fieldClass)) {
311 | fieldType = InternalsHelper.typeOf(field, 1);
312 | } else if (Collection.class.isAssignableFrom(fieldClass)) {
313 | fieldType = InternalsHelper.typeOf(field, 0);
314 | }
315 |
316 | InternalsHelper.setField(field, instance, adaptIn(readingSection, name, fieldClass, fieldType));
317 | }
318 |
319 | if (selfField != null) {
320 | InternalsHelper.setField(selfField, instance, readingSection);
321 | }
322 |
323 | return instance;
324 | }
325 |
326 | ObjectAdapter adapter;
327 |
328 | try {
329 | adapter = (ObjectAdapter) oldAdapter;
330 | } catch (ClassCastException ex) {
331 | throw new ClassStructureException(ex);
332 | }
333 |
334 | return adapter.read(key, section);
335 | }
336 |
337 | public static String translateAlternateColorCodes(char colorChar, char altColorChar, String textToTranslate) {
338 | char[] b = textToTranslate.toCharArray();
339 | for (int i = 0; i < b.length - 1; i++) {
340 | if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
341 | b[i] = colorChar;
342 | b[i+1] = Character.toLowerCase(b[i+1]);
343 | }
344 | }
345 | return new String(b);
346 | }
347 | }
348 |
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/internal/adapt/ObjectAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.internal.adapt;
17 |
18 | import org.bukkit.configuration.ConfigurationSection;
19 |
20 | public interface ObjectAdapter {
21 | I read(String key, ConfigurationSection section);
22 | O write(I obj);
23 | }
--------------------------------------------------------------------------------
/src/main/java/xyz/mkotb/configapi/internal/adapt/impl/ArrayAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Mazen Kotb, mazenkotb@gmail.com
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software for any
5 | * purpose with or without fee is hereby granted, provided that the above
6 | * copyright notice and this permission notice appear in all copies.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 | */
16 | package xyz.mkotb.configapi.internal.adapt.impl;
17 |
18 | import org.bukkit.configuration.ConfigurationSection;
19 | import org.bukkit.configuration.MemoryConfiguration;
20 | import org.bukkit.configuration.MemorySection;
21 | import xyz.mkotb.configapi.internal.InternalsHelper;
22 | import xyz.mkotb.configapi.internal.SerializableMemorySection;
23 | import xyz.mkotb.configapi.internal.adapt.AdapterHandler;
24 | import xyz.mkotb.configapi.internal.adapt.ObjectAdapter;
25 |
26 | import java.lang.reflect.Array;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | public class ArrayAdapter implements ObjectAdapter