You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/articles/configuration/hocon.md
+4-167Lines changed: 4 additions & 167 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,9 +253,9 @@ Substitution processing is performed as the last parsing step, so a substitution
253
253
254
254
If a key has been specified more than once, the substitution will always evaluate to its latest-assigned value (that is, it will evaluate to the merged object, or the last non-object value that was set, in the entire document being parsed including all included files).
255
255
256
-
If a substitution does not match any value present in the configuration and is not resolved by an external source, then it is undefined. An undefined _required substitution_ is invalid and will generate an error.
256
+
If a substitution does not match any value present in the configuration, then it is undefined. An undefined _required substitution_ is invalid and will generate an error.
An application can explicitly block looking up a substitution in the environment by setting a value in the configuration, with the same name as the environment variable. You could set `HOME : null` in your root object to avoid expanding `${HOME}` from the environment, for example:
It's recommended that HOCON keys always use lowercase, because environment variables generally are capitalized. This avoids naming collisions between environment variables and configuration properties. (While on Windows `Environment.GetEnvironmentVariable()` is generally not case-sensitive, the lookup will be case sensitive all the way until the env variable fallback lookup is reached).
289
-
290
-
Environment variables are interpreted as follows:
291
-
292
-
* Env variables set to the empty string are kept as such (set to empty string, rather than undefined)
293
-
* If `Environment.GetEnvironmentVariable()` throws SecurityException, then it is treated as not present
294
-
* Encoding is handled by C# (`Environment.GetEnvironmentVariable()` already returns a Unicode string)
295
-
* Environment variables always become a string value, though if an app asks for another type automatic type conversion would kick in
296
-
297
-
##### Note on Windows and Case Sensitivity of Environment Variables
298
-
299
-
HOCON's lookup of environment variable values is always case sensitive, but Linux and Windows differ in their handling of case.
300
-
301
-
Linux allows one to define multiple environment variables with the same name but with different case; so both "PATH" and "Path" may be defined simultaneously. HOCON's access to these environment variables on Linux is straightforward; ie just make sure you define all your vars with the required case.
302
-
303
-
Windows is more confusing. Windows environment variables names may contain a mix of upper and lowercase characters, eg "Path", however Windows does not allow one to define multiple instances of the same name but differing in case.
304
-
Whilst accessing env vars in Windows is case insensitive, accessing env vars in HOCON is case sensitive.
305
-
306
-
So if you know that you HOCON needs "PATH" then you must ensure that the variable is defined as "PATH" rather than some other name such as "Path" or "path".
307
-
However, Windows does not allow us to change the case of an existing env var; we can't simply redefine the var with an upper case name.
308
-
The only way to ensure that your environment variables have the desired case is to first undefine all the env vars that you will depend on then redefine them with the required case.
309
-
310
-
For example, the the ambient environment might have this definition ...
311
-
312
-
```cmd
313
-
set Path=A;B;C
314
-
```
315
-
316
-
... we just don't know. But if the HOCON needs "PATH", then the start script must take a precautionary approach and enforce the necessary case as follows ...
317
-
318
-
```cmd
319
-
set OLDPATH=%PATH%
320
-
set PATH=
321
-
set PATH=%OLDPATH%
322
-
```
323
-
324
-
You cannot know what ambient environment variables might exist in the ambient environment when your program is invoked, nor what case those definitions might have. Therefore the only safe thing to do is redefine all the vars you rely on as shown above.
325
-
326
-
#### Self-Referential Substitutions
327
-
328
-
The idea of self-referential substitution is to allow a new value for a field to be based on the older value.
Note that an object or array with a substitution inside it is **not** considered self-referential for this purpose. The self-referential rules do **not** apply to:
347
-
348
-
*`a : { b : ${a} }`
349
-
*`a : [${a}]`
350
-
351
-
These cases are unbreakable cycles that generate an error.
Fields may have `+=` as a separator rather than `:` or `=`. A field with `+=` transforms into a self-referential array
360
-
concatenation, like this:
361
-
362
-
a += b
363
-
364
-
becomes:
365
-
366
-
a = ${?a} [b]
367
-
368
-
`+=` appends an element to a previous array. If the previous value was not an array, an error will result just as it would in the long form `a = ${?a} [b]`. Note that the previous value is optional (`${?a}` not `${a}`), which allows `a += b` to be the first mention of `a` in the file (it is not necessary to have `a = []` first).
In isolation (with no merges involved), a self-referential field is an error because the substitution cannot be resolved:
377
-
378
-
foo : ${foo} // an error
379
-
380
-
When `foo : ${foo}` is merged with an earlier value for `foo`, however, the substitution can be resolved to that earlier value. When merging two objects, the self-reference in the overriding field refers to the overridden field. Say you have:
381
-
382
-
foo : { a : 1 }
383
-
foo : ${foo}
384
-
385
-
Then `${foo}` resolves to `{ a : 1 }`, the value of the overridden field.
386
-
387
-
It would be an error if these two fields were reversed, so:
388
-
389
-
foo : ${foo}
390
-
foo : { a : 1 }
391
-
392
-
Here the `${foo}` self-reference comes before `foo` has a value, so it is undefined, exactly as if the substitution referenced a path not found in the document.
393
-
394
-
Because `foo : ${foo}` conceptually looks to previous definitions of `foo` for a value, the optional substitution syntax `${?foo}` does not create a cycle:
395
-
396
-
foo : ${?foo} // this field just disappears silently
397
-
398
-
If a substitution is hidden by a value that could not be merged with it (by a non-object value) then it is never evaluated and no error will be reported. So for example:
399
-
400
-
foo : ${does-not-exist}
401
-
foo : 42
402
-
403
-
In this case, no matter what `${does-not-exist}` resolves to, we know `foo` is `42`, so `${does-not-exist}` is never evaluated and there is no error. The same is true for cycles like `foo : ${foo}, foo : 42`, where the initial self-reference are simply ignored.
404
-
405
-
A self-reference resolves to the value "below" even if it's part of a path expression. So for example:
406
-
407
-
foo : { a : { c : 1 } }
408
-
foo : ${foo.a}
409
-
foo : { a : 2 }
410
-
411
-
Here, `${foo.a}` would refer to `{ c : 1 }` rather than `2` and so the final merge would be `{ a : 2, c : 1 }`.
412
-
413
-
Recall that for a field to be self-referential, it must have a substitution or value concatenation as its value. If a field has an object or array value, for example, then it is not self-referential even if there is a reference to the field itself inside that object or array.
414
-
415
-
Substitution can refer to paths within themselves, for example:
416
-
417
-
bar : { foo : 42,
418
-
baz : ${bar.foo}
419
-
}
420
-
421
-
Because there is no inherent cycle here, the substitution will "look forward" (including looking at the field currently being defined). To make this clearer, in the example below, `bar.baz` would be `43`:
422
-
423
-
bar : { foo : 42,
424
-
baz : ${bar.foo}
425
-
}
426
-
bar : { foo : 43 }
427
-
428
-
Mutually-referring objects would also work, and are not self-referential (so they look forward):
429
-
430
-
// bar.a will end up as 4 and foo.c will end up as 3
431
-
bar : { a : ${foo.d}, b : 1 }
432
-
bar.b = 3
433
-
foo : { c : ${bar.b}, d : 2 }
434
-
foo.d = 4
435
-
436
-
One tricky case is an optional self-reference in a value concatenation, in this example `a` would be `foo` not `foofoo` because the self reference has to "look back" to an undefined `a`:
0 commit comments