What are common pitfalls with -P values regarding empty/boolean values and reading absent properties?
answer
- project properties are always String
- -Pflag → empty string, not true
- hasProperty for presence flags
- property() throws, findProperty() null
- providers...getOrElse for defaults
basics
~10 s-P values are always strings. -Pflag with no =value yields an empty string, not a boolean true. Reading an absent property with project.property() throws; findProperty() returns null.
solid answer
~40 sThree traps. First, **everything is a string**: `-PmaxWorkers=4` gives the string "4", so compare or convert deliberately (`prop.toInt()`), never assume a number or boolean. Second, **bare `-Pflag` is not boolean true** — it sets the property to an empty string, so `if (project.hasProperty("flag"))` is truthy even though the value is ""; test presence with `hasProperty`/`findProperty != null`, not the value, when you mean a flag. Third, **absent-property access differs**: `project.property("x")` throws `MissingPropertyException` if `x` was never set, while `project.findProperty("x")` returns null and `providers.gradleProperty("x")` yields a Provider whose `.orNull` is null. The same string-typing and presence semantics apply whether the property came from `-P`, `ORG_GRADLE_PROJECT_`, or gradle.properties, since they all feed the one project-property table.
code
kotlin · 8 lines// presence flag (don't read the value):
val ci = project.hasProperty("ci") // -Pci -> true, value is ""
// typed value with default:
val workers = (findProperty("workers") as String?)?.toInt() ?: 2
// mandatory value, fail fast:
val version = project.property("version") // throws if absentgo deeper
Recall that -P values are strings and that property() throws while findProperty() returns null.
Explain the bare-flag-empty-string trap and choose the right accessor for mandatory vs optional values.
Standardize parsing/defaulting via providers.gradleProperty().getOrElse and presence-based flags, noting all channels share one string-typed table.
Mandate consistent property-reading helpers across builds so typing and presence semantics are uniform and misconfiguration fails fast.
## All project properties are strings Whatever channel sets a project property — `-Px=4`, `ORG_GRADLE_PROJECT_x=4`, or `x=4` in gradle.properties — the value arrives as a **`String`**. There is no implicit numeric or boolean coercion: ```kotlin val workers = (findProperty("maxWorkers") as String?)?.toInt() ?: 2 val debug = findProperty("debug")?.toString().toBoolean() // "true" -> true ``` ## Bare -Pflag sets an empty string, not true Writing `-PenableX` with no `=value` registers `enableX` with the value `""` (empty string). Therefore: - `project.hasProperty("enableX")` → **true** (it exists) - the value is `""`, which is NOT the boolean `true` So a flag check must test **presence**, not the value: ```kotlin val enabled = project.hasProperty("enableX") // presence-based flag // NOT: findProperty("enableX") == "true" (it's "") ``` If you instead want a true/false value, pass it explicitly: `-PenableX=true` and parse with `.toBoolean()`. ## Absent-property access semantics | Accessor | If property is missing | |----------|------------------------| | `project.property("x")` | throws `MissingPropertyException` | | `project.findProperty("x")` | returns `null` | | `project.hasProperty("x")` | returns `false` | | `providers.gradleProperty("x")` | Provider; `.orNull` = null, `.get()` throws | Pick the accessor that matches your intent: `property()` when the value is mandatory (fail fast), `findProperty()`/`providers...orNull` when it's optional with a default. ## Providing defaults cleanly ```kotlin val env = providers.gradleProperty("env").getOrElse("local") ``` ## Why this matters These pitfalls cause silent misconfiguration: a numeric option treated as a string, a flag that's always "on" because its empty value is truthy in a presence check used as a value check, or a build that throws on a missing optional property. Knowing the string-only typing and the three absent-access behaviors lets you read injected properties safely regardless of which channel set them.
- What value does -PenableCache (no =) give the property enableCache?An empty string "". The property exists (hasProperty is true) but its value is not the boolean true, so use a presence check for flags.
- Difference between project.property("x") and findProperty("x") when x is absent?property("x") throws MissingPropertyException; findProperty("x") returns null. Use property() for mandatory inputs and findProperty for optional ones.
saying these in an interview costs you the question
- Assuming -P numeric/boolean values are typed rather than strings.
- Treating a bare -Pflag as boolean true.
- Using project.property() for an optional property and getting a surprise exception.