├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
├── java
│ └── io
│ │ └── advantageous
│ │ └── config
│ │ ├── Config.java
│ │ ├── ConfigFromObject.java
│ │ ├── ConfigLoader.java
│ │ ├── ConfigMemorySize.java
│ │ ├── Configs.java
│ │ ├── MemorySizeUnit.java
│ │ └── ResourceUtils.java
└── resources
│ └── jjs-config-utils.js
└── test
├── java
└── io
│ └── advantageous
│ └── config
│ ├── ConfigImplTest.java
│ ├── ConfigMemorySizeTest.java
│ ├── JsConfigTest.java
│ ├── JsLoadTest.java
│ └── MemorySizeUnitTest.java
└── resources
├── bad-config.js
├── reference.js
└── test-config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific stuff:
2 | .idea/
3 | /out/
4 | .idea_modules/
5 |
6 | ### Node template
7 | # Logs
8 | logs
9 | *.log
10 | npm-debug.log*
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 |
17 | # Dependency directories
18 | node_modules
19 | jspm_packages
20 |
21 | # Optional npm cache directory
22 | .npm
23 |
24 | # Optional REPL history
25 | .node_repl_history
26 |
27 | ### Gradle template
28 | .gradle
29 | build/
30 |
31 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
32 | !gradle-wrapper.jar
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [Konf Website](http://advantageous.github.io/konf/)
2 |
3 | # Konf - Typed Java Config system
4 | Java configuration library similar in concept to TypeSafe config,
5 | but uses full
6 |
7 | * YAML
8 | * JSON
9 | * JSON Lax
10 | * JavaScript (useful to create Config DSLs, and basic config logic)
11 | * Java Pojos (Pojos, Lists, Maps, basic types)
12 | * TypeSafe Config
13 | * Java properties
14 |
15 | You can also mix and match TypeSafe Config.
16 |
17 | ***Konf*** allows you to easily create your own
18 | [config DSLs](https://github.com/advantageous/konf/wiki/Config-Logic---creating-your-own-config-DSL)
19 | something that is not possible with ***TypeSafe Config***.
20 |
21 |
22 | ## Using Konf on your project
23 |
24 | Konf is in the [public maven repo](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.advantageous.konf%22).
25 |
26 | ### Using konf from maven
27 | ```xml
28 |
29 | io.advantageous.konf
30 | konf
31 | 1.3.0.RELEASE
32 |
33 | ```
34 |
35 | ### Using konf from gradle
36 | ```java
37 | compile 'io.advantageous.konf:konf:1.3.0.RELEASE'
38 | ```
39 |
40 | ### Using konf from scala sbt
41 | ```java
42 | libraryDependencies += "io.advantageous.konf" % "konf" % "1.3.0.RELEASE"
43 | ```
44 |
45 | ### Using konf from clojure leiningen
46 | ```lisp
47 | [io.advantageous.konf/konf "1.3.0.RELEASE"]
48 | ```
49 |
50 | Here is an example config for JavaScript.
51 |
52 | Konf expects the `config` variable to be set to a JavaScript object with
53 | properties.
54 |
55 | #### JavaScript based configuration for Java
56 | ```javascript
57 | var config = {
58 |
59 | myUri: uri("http://host:9000/path?foo=bar"),
60 |
61 | someKey: {
62 | nestedKey: 234,
63 | other: "this text"
64 | }
65 |
66 | };
67 | ```
68 |
69 | You can use full JavaScript for configuration as long as you define a
70 | variable called `config` that results in a JavaScript object which
71 | equates to a Java map.
72 |
73 |
74 | ## Defining your own DSL
75 |
76 | You can define you own config DSL for your environment.
77 | We have a [full example that shows you how to create a custom config DSL](https://github.com/advantageous/konf/wiki/Config-Logic---creating-your-own-config-DSL)
78 | for your internal projects. The example uses Mesosphere and Docker PORT
79 | look ups and it is from a real project.
80 |
81 | #### Defining your own config DSL
82 | ```javascript
83 | var config = {
84 |
85 | platform: {
86 |
87 | statsd: "udp://" + getDockerHost() + ":8125",
88 |
89 | servicePort: mesosPortAt(0, 8080),
90 | adminPort: mesosPortAt(1, 9090),
91 | ...
92 | ```
93 |
94 | See the real world for [example that uses Konf to find ports under
95 | Mesosphere](https://github.com/advantageous/konf/wiki/Config-Logic---creating-your-own-config-DSL)
96 | (running in stating or prod) or under Docker (running on
97 | a local developers box).
98 |
99 | ## Overview
100 |
101 | * implemented in plain Java SDK almost no dependencies (sl4j, and reflekt with no others)
102 | * supports files in : YAML, JSON, JSON LAX, JavaScript, Java properties or any tree of Map/List basic types and POJOs
103 | * allows you to easily create your own config DSL
104 | * merges multiple configs across all formats
105 | * can load from configs, from classpath, http, file or just an Java Object tree
106 | * great support for "nesting" (treat any subtree of the config the same as the whole config)
107 | * users can override the config with Java system properties, java -Dmyapp.foo.bar=10 and sysProp
108 | * users can override the config with OS environment variables
109 | * supports configuring an app, with its framework and libraries, all from a single file such as application.yaml
110 | * parses duration and size settings, "512k" or "10 seconds"
111 | * converts types, so if you ask for a boolean and the value is the string "yes", or you ask for a float and the value is an int, it will figure it out.
112 | * API based on immutable Config instances, for thread safety and easy reasoning about config transformations
113 | * extensive test coverage
114 |
115 | This library limits itself to config.
116 | If you want to load config from another source, e.g., database or Redis or MongoDB,
117 | then you would need to write some custom code. The library has nice support for merging
118 | configurations (Configs with fall-backs) so if you build a custom Config
119 | from a custom source it's easy to merge it in. Just implement Config and then use
120 | `config(config...)` to configure your config into a chain of other configs.
121 | This is described at length below see "Loading config files with fallbacks".
122 |
123 | ## License
124 |
125 | The license is Apache 2.0.
126 |
127 | ## Release Notes
128 |
129 | Please see [Release Notes](https://github.com/advantageous/konf/releases), and
130 | [Release Notes In Progress](https://github.com/advantageous/konf/wiki/Release-Notes-Draft)
131 | for the latest releases.
132 |
133 | ## Build
134 |
135 | The build uses gradle and the tests are written in Java; and,
136 | the library itself is plain Java.
137 |
138 | ## Using the Library
139 |
140 | ```java
141 | import io.advantageous.config.ConfigLoader;
142 |
143 | Config conf = ConfigLoader.load("myconfig.js", "reference.js");
144 | int bar1 = conf.getInt("foo.bar");
145 | Config foo = conf.getConfig("foo");
146 | int bar2 = foo.getInt("bar");
147 | ```
148 |
149 | ## Longer Examples
150 |
151 | You can see longer examples in [tests](https://github.com/advantageous/konf/blob/master/src/test/java/io/advantageous/config/JsLoadTest.java)
152 | along with [sample config](https://github.com/advantageous/konf/blob/master/src/test/resources/test-config.js).
153 | You can run these examples by `git cloning` this project and `running gradle test`.
154 |
155 | In brief, as shown in the examples:
156 |
157 | You create a Config instance provided by your application.
158 | You use `ConfigLoader.load()` and you can define your own config system.
159 | You could setup default `reference.yaml` or `reference.json` but you don't have to.
160 | You could just load a single level of config. Config is as complex or as simple
161 | as you need.
162 |
163 | A `Config` can be created with the parser methods in `ConfigLoader.load`
164 | or built up from any POJO object tree or tree of Map/List/Pojos basic value.
165 | It is very flexible. Examples are shown below and linked to below that use
166 | JSON, YAML and allow you to define your own `DSL` like config.
167 | It is very simple and easy to use.
168 |
169 | ## Immutability
170 |
171 | Objects are immutable, so methods on Config which transform the
172 | configuration return a new `Config`.
173 | There is no complex tree of `Config` objects. Just `Config`.
174 | It is pretty simple to use and understand.
175 |
176 |
177 | ## Java interface for Konf is Config.
178 |
179 | The Java interface for Konf is Config.
180 | You can get a sub Config from Config (`getConfig(path)`).
181 | The `path` is always in dot notation (`this.that.foo.bar`).
182 | You can also use:
183 | * `hasPath(path)`
184 | * `getInt(path)`
185 | * `getLong(path)`
186 | * `getDouble(path)`
187 | * `getBoolean(path)` can be true, false, "yes", "no", "on", "off", yes, no, off, on
188 | * `getString(path)`
189 | * `getStringList(path)` gets a list of strings
190 | * `getConfig(path)` gets a sub-config.
191 | * `getMap(path)` gets a map which is a sub-config.
192 | * `getConfigList(path)` gets a list of configs at the location specified.
193 | * `getIntList(path)`
194 | * `getLongList(path)`
195 | * `getDoubleList(path)`
196 | * `getBooleanList(path)`
197 | * `getDuration(path)` gets `java.time.Duration` useful for timeouts
198 | * `getDurationList(path)` gets duration list
199 | * `getUri(path)` gets `java.net.URI` useful for connecting to downstream services
200 | * `getUriList(path)` useful for connecting to downstream services
201 |
202 |
203 | The `getMap` works with JavaScript objects (or Java maps see below for loading config from Java objects, YAML or JSON).
204 | The `getStringList` and `getConfigList` works
205 | with JavaScript array of string and a JavaScript array of JavaScript objects.
206 |
207 | Note you get an exception if the `path` requested is not found.
208 | Use `hasPath(path)` if you think the config path might be missing.
209 |
210 | Here is partial glimpse at the `Config` interface.
211 |
212 | #### Config interface
213 | ```java
214 | public interface Config {
215 |
216 | /** Get string at location. */
217 | String getString(String path);
218 |
219 | /** Checks to see if config has the path specified. */
220 | boolean hasPath(String path);
221 |
222 | /** Get int at location. */
223 | int getInt(String path);
224 |
225 | /** Get float at location. */
226 | float getFloat(String path);
227 |
228 | /** Get double at location. */
229 | double getDouble(String path);
230 |
231 | /** Get long at location. */
232 | long getLong(String path);
233 |
234 | /** Get list of strings at location. */
235 | List getStringList(String path);
236 |
237 | /** Get map at location. */
238 | Map getMap(String path);
239 |
240 | /** Get a sub-config at location. */
241 | Config getConfig(String path);
242 |
243 | /** Get list of sub-configs at location. */
244 | List getConfigList(String path);
245 |
246 | /** Get a single POJO out of config at path. */
247 | T get(String path, Class type);
248 |
249 | /** Get a list of POJOs. */
250 | List getList(String path, Class componentType);
251 |
252 | /** Get duration. Good for timeouts */
253 | Duration getDuration(String path);
254 |
255 | /** Get duration list. */
256 | List getDurationList(String path);
257 |
258 | /** Get int list. */
259 | List getIntegerList(String path);
260 | ...
261 | }
262 |
263 | ```
264 |
265 | The `getX` methods work like you would expect. Given this config file.
266 |
267 | ## JavaScript functions for config
268 |
269 | #### JavaScript functions that we support
270 | * `sysProp(propName)` to read a sysProp as in `fooSize : sysProp("my.foo.size")`
271 | * `sysPropOrDefault(propName, defaultValue)` to read a sysProp or a default
272 | * `isWindowsOS()`, `isMacOS()`, `isUnix()`, `isLinux()`, `isSolaris()`
273 | * `env()` as in `fooSize : env('MY_FOO_SIZE')` or even `fooSize : sysPropOrDefault("my.foo.size", env('MY_FOO_SIZE'))`
274 | * `uri()` which creates a `java.net.URI` as in `fooURI : uri ("http://localhost:8080/")`
275 | * `java.time.Duration` is imported as `duration`
276 | * `java.lang.System` is imported as `system`
277 | * `seconds(units)`, `minutes(units)`, `hours(units)`, `days(units)`, `millis(units)` and `milliseconds(units`) define a `Duration` which is useful for configuring timeouts and interval jobs
278 | * constants `yes`, `no`, `on`, `off` for boolean config
279 | * `load(resources...)` load a config
280 | * `configs(config...)` chain a group of configs
281 | * `bytes(units)`, `kilobytes(units)`, `megabytes(units)`, `gigabytes(units)` to read sizes
282 |
283 | #### Sample config for testing and showing how config works
284 |
285 | ```javascript
286 | var config = {
287 |
288 | myUri: uri("http://host:9000/path?foo=bar"),
289 |
290 | someKey: {
291 | nestedKey: 234,
292 | other: "this text"
293 | },
294 |
295 | int1: 1,
296 | float1: 1.0,
297 | double1: 1.0,
298 | long1: 1,
299 | string1: "rick",
300 | stringList: ['Foo', 'Bar'],
301 | configInner: {
302 | int2: 2,
303 | float2: 2.0
304 | },
305 | uri: uri("http://localhost:8080/foo"),
306 | myClass: "java.lang.Object",
307 | myURI: "http://localhost:8080/foo",
308 | employee: {"id": 123, "name": "Geoff"},
309 | employees: [
310 | {id: 123, "name": "Geoff"},
311 | {id: 456, "name": "Rick"},
312 | {id: 789, 'name': "Paul"}
313 | ]
314 | };
315 |
316 | ```
317 |
318 |
319 | We can do the following operations.
320 |
321 | First we load the config.
322 |
323 | #### Loading the config.
324 |
325 | ```java
326 |
327 | private Config config;
328 |
329 | @Before
330 | public void setUp() throws Exception {
331 | config = ConfigLoader.load("test-config.js");
332 | }
333 | ```
334 |
335 | Note that `ConfigLoader.load(resources...)` takes a variable length string array.
336 | By default a resource String can contain a valid URI, which
337 | can have the scheme `classpath`, `file`, or `http`. If you do not specify
338 | a scheme than the path is assumed to be a classpath resource.
339 |
340 | #### Using different resources
341 |
342 | ```java
343 | config = ConfigLoader.load(
344 | "/io/mycompany/foo-classpath.js",
345 | "classpath:test-config.js",
346 | "classpath://foo.js",
347 | "classpath:/bar.js",
348 | "file://opt/app/config.js",
349 | "file:///opt/app/config2.js",
350 | "file:/opt/app/config.js",
351 | "http://my.internal.server:9090/foo.js"
352 | );
353 |
354 | ```
355 |
356 | Then we show reading basic types with the `config` object using `getX`.
357 |
358 | #### Reading basic types from config
359 |
360 | ```java
361 | @Test
362 | public void testSimple() throws Exception {
363 |
364 | //getInt
365 | assertEquals(1, config.getInt("int1"));
366 |
367 | //getStringList
368 | assertEquals(asList("Foo", "Bar"),
369 | config.getStringList("stringList"));
370 |
371 | //getString
372 | assertEquals("rick", config.getString("string1"));
373 |
374 | //getDouble
375 | assertEquals(1.0, config.getDouble("double1"), 0.001);
376 |
377 | //getLong
378 | assertEquals(1L, config.getLong("long1"));
379 |
380 | //getFloat
381 | assertEquals(1.0f, config.getFloat("float1"), 0.001);
382 |
383 | //Basic JDK value types are supported like class.
384 | assertEquals(Object.class, config.get("myClass", Class.class));
385 |
386 | //Basic JDK value types are supported like URI.
387 | assertEquals(URI.create("http://localhost:8080/foo"),
388 | config.get("myURI", URI.class));
389 |
390 | assertEquals(URI.create("http://localhost:8080/foo"),
391 | config.get("uri", URI.class));
392 |
393 | }
394 |
395 | ```
396 |
397 | You can work with nested properties as well.
398 |
399 | #### Reading a nested config from the config
400 |
401 | ```java
402 | @Test
403 | public void testGetConfig() throws Exception {
404 | //Read nested config.
405 | final Config configInner = config.getConfig("configInner");
406 | assertEquals(2, configInner.getInt("int2"));
407 | assertEquals(2.0f, configInner.getFloat("float2"), 0.001);
408 | }
409 |
410 | @Test
411 | public void testGetMap() throws Exception {
412 | //Read nested config as a Java map.
413 | final Map map = config.getMap("configInner");
414 | assertEquals(2, (int) map.get("int2"));
415 | assertEquals(2.0f, (double) map.get("float2"), 0.001);
416 | }
417 | ```
418 |
419 | You can read deeply nested config items as well by specifying the
420 | property path using dot notation.
421 |
422 | #### Reading nested properties with dot notation from config
423 |
424 |
425 | ```java
426 | @Test
427 | public void testSimplePath() throws Exception {
428 |
429 | assertTrue(config.hasPath("configInner.int2"));
430 | assertFalse(config.hasPath("configInner.foo.bar"));
431 | assertEquals(2, config.getInt("configInner.int2"));
432 | assertEquals(2.0f, config.getFloat("configInner.float2"), 0.001);
433 | }
434 | ```
435 |
436 | You can also read POJOs directly out of the config file.
437 |
438 | #### Reading a pojo directly out of the config file
439 | ```java
440 |
441 | @Test
442 | public void testReadClass() throws Exception {
443 | final Employee employee = config.get("employee", Employee.class);
444 | assertEquals("Geoff", employee.name);
445 | assertEquals("123", employee.id);
446 | }
447 |
448 | ```
449 |
450 | You can read a list of POJOs at once.
451 |
452 | #### Reading a pojo list directly out of the config file
453 | ```java
454 |
455 | @Test
456 | public void testReadListOfClass() throws Exception {
457 | final List employees = config.getList("employees", Employee.class);
458 | assertEquals("Geoff", employees.get(0).name);
459 | assertEquals("123", employees.get(0).id);
460 | }
461 | ```
462 |
463 | You can also read a list of config objects out of the config as well.
464 |
465 | #### Reading a config list directly out of the config file
466 | ```java
467 |
468 | final List employees = config.getConfigList("employees");
469 | assertEquals("Geoff", employees.get(0).getString("name"));
470 | assertEquals("123", employees.get(0).getString("id"));
471 | ```
472 |
473 | ## Using Config with YAML
474 |
475 | First include a YAML to object parser like [YAML Beans](https://github.com/EsotericSoftware/yamlbeans)
476 | or a library like this.
477 |
478 | #### Example YAML
479 |
480 | ```yaml
481 | name: Nathan Sweet
482 | age: 28
483 | address: 4011 16th Ave S
484 | phone numbers:
485 | - name: Home
486 | number: 206-555-5138
487 | - name: Work
488 | number: 425-555-2306
489 | ```
490 |
491 | #### Using Konf with YAML
492 |
493 | ```java
494 | //Use YamlReader to load YAML file.
495 | YamlReader reader = new YamlReader(new FileReader("contact.yml"));
496 |
497 | //Convert object read from YAML into Konf config
498 | Config config = ConfigLoader.loadFromObject(reader.read());
499 |
500 | //Now you have strongly typed access to fields
501 | String address = config.getString("address");
502 | ```
503 |
504 | You can also read Pojos from anywhere in the YAML file as well as
505 | sub configs.
506 |
507 |
508 | ## You can also use Konf with JSON using Boon
509 |
510 | See [Boon](https://github.com/advantageous/boon) JSON parser project,
511 | and [Boon in five minutes](https://github.com/boonproject/boon/wiki/Boon-JSON-in-five-minutes)
512 |
513 | #### Using Konf with JSON
514 |
515 | ```java
516 | ObjectMapper mapper = JsonFactory.create();
517 |
518 |
519 | /* Convert object read from YAML into Konf config.
520 | 'src' can be File, InputStream, Reader, String. */
521 | Config config = ConfigLoader.loadFromObject(mapper.fromJson(src));
522 |
523 |
524 | //Now you have strongly typed access to fields
525 | String address = config.getString("address");
526 |
527 | ```
528 |
529 | Boon supports LAX JSON (Json with comments, and you do not need to quote
530 | the field).
531 |
532 |
533 | #### Working with java.time.Duration
534 |
535 | * `getDuration(path)` get a duration
536 | * `getDurationList(path)` get a duration list
537 |
538 | Konf supports "10 seconds" style config for duration as well as
539 | having built-in functions and support for ISO-8601. See documentation
540 | for [duration config](https://github.com/advantageous/konf/wiki/Working-with-Durations)
541 | for more details.
542 |
543 | ##### Konf can reads list of numbers.
544 |
545 | * `getIntList` reads list of ints
546 | * `getLongList` reads list of longs
547 | * `getDoubleList` reads list of doubles
548 | * `getFloatList` reads list of floats
549 |
550 | See documentation [list of number configuration](https://github.com/advantageous/konf/wiki/Working-with-lists-of-ints,-longs,-doubles,)
551 | for more details.
552 |
553 | #### Konf can read memory sizes
554 |
555 | * `getMemorySize(path)`
556 | * `getMemorySizeList(path)`
557 |
558 |
559 |
560 | This means we support config like:
561 |
562 | #### Sizes supported.
563 | ```javascript
564 |
565 | diskSpace : " 10 gigabytes",
566 | diskVolumes : [" 10 gigabytes", "10GB", "10 gigabytes", 10]
567 | ```
568 |
569 | We support the following size Strings.
570 |
571 | #### Supported size strings
572 | ```java
573 |
574 | public enum MemorySizeUnit {
575 |
576 | BYTES(1, "B", "b", "byte", "bytes"),
577 | KILO_BYTES(1_000, "kB", "kilobyte", "kilobytes"),
578 | MEGA_BYTES(1_000_000, "MB", "megabyte", "megabytes"),
579 | GIGA_BYTES(1_000_000_000, "GB", "gigabyte", "gigabytes"),
580 | TERA_BYTES(1_000_000_000, "TB", "terabyte", "terabytes"),
581 | PETA_BYTES(1_000_000_000_000L, "PB", "petabyte", "petabytes"),
582 | EXA_BYTES(1_000_000_000_000_000L, "EB", "exabyte", "exabytes"),
583 | ZETTA_BYTES(1_000_000_000_000_000_000L, "ZB", "zettabyte", "zettabytes");
584 |
585 | ```
586 |
587 | You can also specify the sizes with built-in functions if you don't
588 | want to use strings.
589 |
590 | #### Using built-in functions to create sizes.
591 | ```javascript
592 | diskVolumes: [kilobytes(10), megabytes(10), bytes(10), gigabytes(10)]
593 | ```
594 |
595 | ## Loading config files with fallbacks
596 |
597 | ####
598 | ```java
599 |
600 | import static io.advantageous.config.ConfigLoader.*;
601 | ...
602 | private Config config;
603 | ...
604 | config = configs(config("test-config.js"), config("reference.js"));
605 |
606 | ```
607 |
608 | You can load config. The `config` method is an alias for `load(resources...)`.
609 | The `configs(config...)` creates a series of configs where the configs
610 | are search from left to right. The first config that has the object (starting
611 | from the left or 0 index) will return the object.
612 |
613 | Give the following two configs (from the above example).
614 |
615 | #### test-config.js
616 | ```javascript
617 | var config = {
618 | abc : "abc",
619 | ```
620 |
621 |
622 | #### reference.js
623 | ```javascript
624 | var config = {
625 | abc : "abcFallback",
626 | def : "def"
627 | }
628 | ```
629 |
630 | You could run this test.
631 |
632 | #### Testing the reference.js is a fallback for test-config.js.
633 |
634 | ```java
635 |
636 | import static io.advantageous.config.ConfigLoader.*;
637 | ...
638 |
639 | config = configs(config("test-config.js"), config("reference.js"));
640 |
641 | final String value = config.getString("abc");
642 | assertEquals("abc", value);
643 |
644 | final String value1 = config.getString("def");
645 | assertEquals("def", value1);
646 | ```
647 |
648 | You can load your config anyway you like. The String `abc` is found
649 | when looking up the key `abc` because it is in the `test-config.js` which
650 | gets read before the value `abcFallback` which is in `reference.js`.
651 | Yet the `def` key yields the `"def"` because it is defined in `reference.js`
652 | but not `test-config.js`. You can implement the same style config reading and
653 | fallback as is in Type Safe Config but with your DSL.
654 |
655 |
656 | #### Using Konf with Typesafe Config
657 |
658 | This allows you to combine TypeSafe `Config` and Konf `Config`.
659 | You can have TypeSafe config be a fallback for Konf or the other way around.
660 |
661 |
662 | You can load TypeSafe `Config` as a Konf `Config` instance as follows:
663 |
664 | #### Loading Typesafe config as a Konf Config object
665 | ```java
666 |
667 | Config config = TypeSafeConfig.typeSafeConfig();
668 | final String abc = config.getString("abc");
669 | assertEquals("abc", abc);
670 | ```
671 |
672 | You can also chain TypeSafe config as fallback or Konf `Config` as a fallback
673 | for TypeSafe `Config` as follows:
674 |
675 |
676 | #### Konf as a fallback for TypeSafe config.
677 |
678 | ```java
679 |
680 |
681 | import static io.advantageous.config.ConfigLoader.config;
682 | import static io.advantageous.config.ConfigLoader.configs;
683 | import static io.advantageous.config.ConfigLoader.load;
684 |
685 | ...
686 |
687 | Config config;
688 | ...
689 | config = configs(TypeSafeConfig.typeSafeConfig(), config("test-config.js"));
690 | ```
691 |
692 | #### TypeSafe config as a fallback for Konf.
693 |
694 | ```java
695 |
696 |
697 | import static io.advantageous.config.ConfigLoader.config;
698 | import static io.advantageous.config.ConfigLoader.configs;
699 | import static io.advantageous.config.ConfigLoader.load;
700 |
701 | ...
702 |
703 | Config config;
704 | ...
705 | config = configs(config("test-config.js"), TypeSafeConfig.typeSafeConfig());
706 | ```
707 |
708 | You can convert any TypeSafe `Config` into a Konf `Config` by using
709 | `TypeSafeConfig.fromTypeSafeConfig(typeSafeConfig)`.
710 |
711 | Find out more about TypeSafe config support at [Konf TypeSafe config](http://advantageous.github.io/konf-typesafe-config/).
712 |
713 | #### Thanks
714 |
715 | If you like our configuration project, please try our
716 | [Reactive Java project](https://github.com/advantageous/reakt)
717 | or our [Actor based microservices lib](https://github.com/advantageous/qbit).
718 |
719 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright (c) 2016. Rick Hightower, Geoff Chandler
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | group 'io.advantageous.konf'
20 | version '1.3.8'
21 |
22 | apply plugin: 'java'
23 | apply plugin: 'maven'
24 | apply plugin: 'signing'
25 | apply plugin: 'idea'
26 |
27 | task wrapper(type: Wrapper) {
28 | gradleVersion = '2.11'
29 | }
30 |
31 | test.onlyIf { !Boolean.getBoolean('skip.tests') }
32 |
33 | repositories {
34 | mavenCentral()
35 | }
36 |
37 | sourceCompatibility = JavaVersion.VERSION_1_8
38 | targetCompatibility = JavaVersion.VERSION_1_8
39 |
40 | dependencies {
41 | compile 'org.slf4j:slf4j-api:1.7.14'
42 | compile 'io.advantageous.boon:boon-util:0.5.7'
43 | testCompile group: 'junit', name: 'junit', version: '4.11'
44 | }
45 |
46 | task javadocJar(type: Jar, dependsOn: javadoc) {
47 | classifier = 'javadoc'
48 | from 'build/docs/javadoc'
49 | }
50 |
51 | task sourcesJar(type: Jar) {
52 | from sourceSets.main.allSource
53 | classifier = 'sources'
54 | }
55 |
56 | artifacts {
57 | archives jar
58 | archives javadocJar
59 | archives sourcesJar
60 | }
61 |
62 | signing {
63 | required false
64 | sign configurations.archives
65 | }
66 |
67 | uploadArchives {
68 | repositories {
69 | mavenDeployer {
70 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
71 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
72 | try {
73 | authentication(userName: sonatypeUsername, password: sonatypePassword)
74 | } catch (MissingPropertyException ignore) {
75 | }
76 | }
77 |
78 | pom.project {
79 | packaging 'jar'
80 | name project.name
81 | description "Java configuration using JavaScript."
82 |
83 | url 'https://github.com/advantageous/konf'
84 |
85 | scm {
86 | url 'scm:git@github.com:advantageous/konf.git'
87 | connection 'scm:git@github.com:advantageous/konf.git'
88 | developerConnection 'scm:git@github.com:advantageous/konf.git'
89 | }
90 |
91 | licenses {
92 | license {
93 | name 'The Apache Software License, Version 2.0'
94 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
95 | distribution 'repo'
96 | }
97 | }
98 |
99 | developers {
100 | developer {
101 | id 'richardHightower'
102 | name 'Richard Hightower'
103 | }
104 | developer {
105 | id 'sailorgeoffrey'
106 | name 'Geoffrey Chandler'
107 | }
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
114 |
115 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/advantageous/konf/51f773fdee0467d8e4b3aaed3567b8b40b5ca9a7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 26 17:51:47 PDT 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * This settings file was auto generated by the Gradle buildInit task
3 | * by 'gcc' at '4/26/16 5:49 PM' with Gradle 2.11
4 | *
5 | * The settings file is used to specify which projects to include in your build.
6 | * In a single project build this file can be empty or even removed.
7 | *
8 | * Detailed information about configuring a multi-project build in Gradle can be found
9 | * in the user guide at https://docs.gradle.org/2.11/userguide/multi_project_builds.html
10 | */
11 |
12 | /*
13 | // To declare projects as part of a multi-project build use the 'include' method
14 | include 'shared'
15 | include 'api'
16 | include 'services:webservice'
17 | */
18 |
19 | rootProject.name = 'konf'
20 |
--------------------------------------------------------------------------------
/src/main/java/io/advantageous/config/Config.java:
--------------------------------------------------------------------------------
1 | package io.advantageous.config;
2 |
3 | import java.net.URI;
4 | import java.time.Duration;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | /**
9 | * Configuration Interface
10 | *
11 | * @author Rick Hightower
12 | * @author Geoff Chandler
13 | */
14 | @SuppressWarnings("WeakerAccess")
15 | public interface Config {
16 |
17 |
18 | /**
19 | * Get a ConfigMemorySize at location
20 | *
21 | * @param path path
22 | * @return string at location.
23 | */
24 | ConfigMemorySize getMemorySize(String path);
25 |
26 | /**
27 | * Get a ConfigMemorySize list at location
28 | *
29 | * @param path path
30 | * @return string at location.
31 | */
32 | List getMemorySizeList(String path);
33 |
34 | /**
35 | * Get a URI at location
36 | *
37 | * @param path path
38 | * @return string at location./
39 | */
40 | URI getUri(String path);
41 |
42 | /**
43 | * Get a list of URI at location
44 | *
45 | * @param path path
46 | * @return string at location.
47 | */
48 | List getUriList(String path);
49 |
50 |
51 | /**
52 | * Get a string at location
53 | *
54 | * @param path path
55 | * @return string at location./
56 | */
57 | String getString(String path);
58 |
59 | /**
60 | * Checks to see if config has the path specified.
61 | *
62 | * @param path path to property.
63 | * @return true if the path exists.
64 | */
65 | boolean hasPath(String path);
66 |
67 | /**
68 | * Get int at location
69 | *
70 | * @param path path to property.
71 | * @return value
72 | */
73 | int getInt(String path);
74 |
75 | /**
76 | * Get boolean at location
77 | *
78 | * @param path path to property.
79 | * @return value
80 | */
81 | boolean getBoolean(String path);
82 |
83 |
84 | /**
85 | * get a boolean list
86 | *
87 | * @param path path to boolean list
88 | * @return boolean list
89 | */
90 | List getBooleanList(String path);
91 |
92 | /**
93 | * Get float at location
94 | *
95 | * @param path path to property.
96 | * @return value
97 | */
98 | float getFloat(String path);
99 |
100 | /**
101 | * Get double at location
102 | *
103 | * @param path path to property.
104 | * @return value
105 | */
106 | double getDouble(String path);
107 |
108 | /**
109 | * Get long at location
110 | *
111 | * @param path path to property.
112 | * @return value
113 | */
114 | long getLong(String path);
115 |
116 |
117 | /**
118 | * Get Duration at location
119 | *
120 | * @param path path to property.
121 | * @return value
122 | */
123 | Duration getDuration(String path);
124 |
125 | /**
126 | * Get Duration at location
127 | *
128 | * @param path path to property.
129 | * @return value
130 | */
131 | List getDurationList(String path);
132 |
133 | /**
134 | * Get list of strings at location
135 | *
136 | * @param path path to list of strings.
137 | * @return value
138 | */
139 | List getStringList(String path);
140 |
141 | /**
142 | * Get list of ints at location
143 | *
144 | * @param path path to list of strings.
145 | * @return value
146 | */
147 | List getIntList(String path);
148 |
149 | /**
150 | * Get list of doubles at location
151 | *
152 | * @param path path to list of strings.
153 | * @return value
154 | */
155 | List getDoubleList(String path);
156 |
157 | /**
158 | * Get list of floats at location
159 | *
160 | * @param path path to list of strings.
161 | * @return value
162 | */
163 | List getFloatList(String path);
164 |
165 | /**
166 | * Get list of doubles at location
167 | *
168 | * @param path path to list of strings.
169 | * @return value
170 | */
171 | List getLongList(String path);
172 |
173 | /**
174 | * Get map at location
175 | *
176 | * @param path path to list of strings.
177 | * @return value
178 | */
179 | Map getMap(String path);
180 |
181 | /**
182 | * Get a single config at location.
183 | *
184 | * @param path path to config
185 | * @return Config at location
186 | */
187 | Config getConfig(String path);
188 |
189 |
190 | /**
191 | * Get list of configs at location.
192 | *
193 | * @param path path to config
194 | * @return Config at location
195 | */
196 | List getConfigList(String path);
197 |
198 | /**
199 | * Get a single POJO.
200 | *
201 | * @param path path
202 | * @param type type
203 | * @param T generic type
204 | * @return a single POJO.
205 | */
206 | T get(String path, Class type);
207 |
208 | /**
209 | * Get a list of POJOs.
210 | *
211 | * @param path path
212 | * @param componentType component type of the pojo
213 | * @param generic type of the POJO.
214 | * @return list of POJOs of type T (type class).
215 | */
216 | List getList(String path, Class componentType);
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/src/main/java/io/advantageous/config/ConfigFromObject.java:
--------------------------------------------------------------------------------
1 | package io.advantageous.config;
2 |
3 | import io.advantageous.boon.core.Conversions;
4 | import io.advantageous.boon.core.Sets;
5 | import io.advantageous.boon.core.Value;
6 | import io.advantageous.boon.core.reflection.Mapper;
7 | import io.advantageous.boon.core.reflection.MapperSimple;
8 | import jdk.nashorn.api.scripting.ScriptObjectMirror;
9 |
10 | import java.math.BigDecimal;
11 | import java.net.URI;
12 | import java.time.Duration;
13 | import java.time.format.DateTimeParseException;
14 | import java.util.*;
15 | import java.util.concurrent.TimeUnit;
16 | import java.util.stream.Collectors;
17 |
18 | import static io.advantageous.boon.core.Maps.map;
19 | import static io.advantageous.boon.core.reflection.BeanUtils.findProperty;
20 | import static java.util.Arrays.asList;
21 | import static java.util.concurrent.TimeUnit.*;
22 |
23 | /**
24 | * Turns any Map or Java Object into config.
25 | * Works with any Java Object tree and or any Nashorn ScriptObjectMirror tree.
26 | *
27 | * @author Rick Hightower
28 | * @author Geoff Chandler
29 | */
30 | class ConfigFromObject implements Config {
31 |
32 | private final Object root;
33 | private final Mapper mapper = new MapperSimple();
34 |
35 | private final Map> timeUnitMap = map(
36 | MICROSECONDS, asList("microseconds", "microsecond", "micros", "micro", "us"),
37 | MILLISECONDS, asList("milliseconds", "millisecond", "millis", "milli", "ms"),
38 | SECONDS, asList("seconds", "second", "s"),
39 | MINUTES, asList("minutes", "minute", "m"),
40 | HOURS, asList("hours", "hour", "h"),
41 | DAYS, asList("days", "day", "d")
42 | );
43 |
44 |
45 | private final Set TRUE = Sets.set("yes", "true", "on");
46 | private final Set FALSE = Sets.set("no", "false", "off");
47 |
48 | ConfigFromObject(T object) {
49 | this.root = object;
50 | }
51 |
52 |
53 | @Override
54 | @SuppressWarnings("unchecked")
55 | public T get(String path, Class type) {
56 | final Object value = validatePath(path);
57 | if (type.isAssignableFrom(value.getClass())) {
58 | return (T) value;
59 | } else if (value instanceof Map) {
60 | final Map map = getMap(path);
61 | return mapper.fromMap(map, type);
62 | } else {
63 | return Conversions.coerce(type, value);
64 | }
65 | }
66 |
67 | @Override
68 | @SuppressWarnings("unchecked")
69 | public List getList(String path, Class componentType) {
70 |
71 | Object value = validatePath(path);
72 | if (value instanceof ScriptObjectMirror) {
73 | value = extractListFromScriptObjectMirror(path, value, Map.class);
74 | }
75 |
76 | if (value instanceof List) {
77 | List