Gatling's reference tells you never to let an IDE optimize the imports of a simulation file — what can that break, and which packages does Gatling treat as its public API?
answer
- Copy the block, never tidy it
- Some members no call site ever names
- Scala implicits and the deploymentInfo field
- Only the named packages are public API
basics
~20 sOptimizing imports drops members no call site names: Scala's implicits on Predef, and Java statics that are read rather than called, such as CoreDsl.deploymentInfo. Gatling's public API is only the packages its import block names; everything else is private.
solid answer
~40 sAn import optimizer deletes what looks unused and narrows a wildcard to the members it can see referenced, and both are unsafe here. In Scala, `io.gatling.core.Predef` carries implicits — the configuration and the duration classes — that no use site mentions by name, so narrowing the wildcard silently removes them. In Java and Kotlin, `HttpDsl.http` is both a static field and an overloaded static method sharing one name — inseparable by import, so the pair is kept or lost whole — `CoreDsl.deploymentInfo` is a field rather than a call, and the DSL methods carry very large overload sets. Gatling's answer is to copy the block verbatim. The same section adds the boundary: any class outside the named packages is private and may change without notice, and `io.gatling.javaapi.core.internal` and `io.gatling.javaapi.http.internal` really exist.
code
scala · 16 linesimport scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class CheckoutSimulation extends Simulation {
private val httpProtocol = http.baseUrl("https://example.com")
private val scn = scenario("checkout")
.exec(http("home").get("/"))
setUp(scn.inject(rampUsers(50).during(30.seconds)))
.protocols(httpProtocol)
.assertions(global.failedRequests.percent.lt(1.0))
}go deeper
Recall the instruction itself: copy Gatling's import block into each simulation rather than letting the editor tidy or shorten it.
Name at least one member that static analysis cannot see used, such as a Scala implicit, and say why the field-and-method pair named http is instead inseparable by import.
Connect the rule to the API boundary: the named packages are the contract, and an import from an internal package is a defect to raise in review.
Decide the policy: which editor settings the load-test source set carries, how the preamble is distributed, and what happens when a test needs something the API does not expose.
Gatling's simulation reference carries an unusual instruction in a box next to the import block: *"Do not try to 'optimize imports' with your IDE, you'd break everything. Just copy-paste those imports wherever you want to use Gatling SDK."* The documentation states the rule without explaining it. The source shows what is at stake. ## What the wildcards actually carry An import optimizer does two things: it deletes imports it believes are unused, and it expands a wildcard into the individual members it can see referenced. Both operations are safe only when every use is visible to static analysis. In a Gatling simulation, several are not. **In Scala**, `io.gatling.core.Predef` is a single object holding three different kinds of member: * DSL methods, inherited because `object Predef extends CoreDsl`; * type aliases — `type Simulation`, `type Session`, `type Status`, `type Assertion`; * **implicits** — `implicit def configuration: GatlingConfiguration`, the implicit classes `DurationInteger` and `DurationJLong`, and, through the `CoreDsl` trait, `CoreDefaultImplicits` and `ValidationImplicits`. The first two categories are named at their use sites, so a tool can see them. The implicits are not named anywhere. Narrowing `import io.gatling.core.Predef._` to the members a tool can see used therefore silently drops the implicit machinery the DSL depends on, and the failure surfaces somewhere unrelated to the line that was edited. **In Java and Kotlin**, the risk is different but real. The preamble pairs a package wildcard with a static wildcard, and each carries members that are easy to attribute wrongly: * `HttpDsl.http` is both a static **field** (the protocol builder) and an overloaded static **method** (`http("name")`, the request builder). The two are inseparable by import, because a single static import brings in every accessible static member with that simple name — `import static io.gatling.javaapi.http.HttpDsl.http;` yields the protocol-builder field *and* both `http(...)` overloads together, and no import form admits one while excluding the other. So the risk here is not a split but a deletion, and the field form, being read rather than called, is the one an optimizer is likeliest to judge unused. * `CoreDsl.deploymentInfo` is a static field, not a method call, and is the kind of member a tool is most likely to consider unused. * The DSL methods carry very large overload sets — `pause`, `pace`, `during`, `feed`, `asLongAsDuring` each have a dozen or more forms — so replacing a wildcard with single-member imports produces a long, fragile list that the next edit invalidates. ## The API boundary the same block draws The identical documentation section carries a second warning: *"Beware that any class that doesn't belong to those packages is considered private, not an API, and hence subject to change at any time without notice."* The packages named in the block are the contract: | SDK | public API packages | |---|---| | Java and Kotlin | `io.gatling.javaapi.core`, `io.gatling.javaapi.http`, and `io.gatling.javaapi.jdbc` / `.jms` / `.redis` when used | | Scala | `io.gatling.core.Predef`, `io.gatling.http.Predef`, and the matching `jdbc` / `jms` / `redis` `Predef` objects | The source confirms the line is drawn deliberately: `io.gatling.javaapi.core.internal` and `io.gatling.javaapi.http.internal` are real subpackages, and a Java single-level wildcard import does not reach into them. Anything a simulation pulls in from an `internal` package, or from a Scala core package such as `io.gatling.core.controller`, is machinery Gatling may change in a patch release without a deprecation cycle. ## What to do instead 1. **Treat the preamble as a fixed block.** Copy it into every simulation. It is short, it is the same everywhere, and it is documented as copy-paste material. 2. **Turn the optimizer off for these files**, or configure it not to collapse or expand wildcard imports in the load-test source set. Whichever mechanism your editor offers, the goal is that nobody's save action rewrites the block. 3. **Make it reviewable.** A simulation whose imports differ from the documented set is worth a second look in review, in either direction: a member missing, or a class imported from outside the API packages. 4. **Treat an import from an `internal` package as a defect**, not a shortcut. If a simulation needs something the API does not expose, the honest outcomes are to restructure the test or to accept that the capability is not public — not to reach past the boundary and discover it at the next upgrade. ## Why this is worth an interview question It is a small rule with a revealing answer. A candidate who says "the IDE would remove unused imports" has half of it. A candidate who can say *which* members are invisible to static analysis — implicits in Scala, a static field such as `deploymentInfo` in Java — is describing the mechanism rather than repeating the warning. And a candidate who connects the same import block to Gatling's public-API boundary has understood that the preamble is a contract, not boilerplate.
- Which members of the Java preamble is an optimizer most likely to get wrong?The ones that are not method calls. `CoreDsl.deploymentInfo` is a static field, so an optimizer that reasons about call sites is the likeliest to judge it unused and delete the import that carries it. `HttpDsl.http` is a static field *and* an overloaded static method sharing one name, and the two cannot be separated — a single static import brings in every static member with that simple name — so the risk there is losing both at once rather than splitting the pair.
- How would you tell whether a simulation has reached outside Gatling's public API?Compare its import block to the documented one. Anything from an `internal` subpackage such as `io.gatling.javaapi.core.internal`, or from a Scala core package like `io.gatling.core.controller`, is outside the contract and may change in a patch release without a deprecation cycle.
saying these in an interview costs you the question
- Treating the Gatling import block as ordinary boilerplate
- Assuming an unused-looking import is genuinely unused
- Importing from an internal package to reach a hidden feature
- Believing a package wildcard also imports its subpackages