skip to content

In JMeter's Java Request sampler, which interface must your class implement and when is each method called?

level: middleimportance: should knowfreq 47%

answer

  1. One interface, four methods
  2. Abstract base class saves writing three of them
  3. Setup happens later than most people think
  4. One method may never be called

basics

~10 s

The class must implement org.apache.jmeter.protocol.java.sampler.JavaSamplerClient. JMeter calls setupTest once before the first sample, runTest for every sample, teardownTest at the end, and getDefaultParameters to populate the sampler's argument table.

solid answer

~40 s

The Java Request sampler drives any class implementing `org.apache.jmeter.protocol.java.sampler.JavaSamplerClient`, and in practice you extend `AbstractJavaSamplerClient` rather than implementing the interface bare. Four methods make up the contract: `getDefaultParameters()` returns an `Arguments` object that seeds the sampler's parameter table in the GUI; `setupTest(JavaSamplerContext)` runs once, lazily, before that sampler instance takes its first sample; `runTest(JavaSamplerContext)` runs for every sample and must return a `SampleResult` you have timed with `sampleStart()`/`sampleEnd()` and marked with `setSuccessful()`; `teardownTest(JavaSamplerContext)` runs at the end. All parameters arrive as Strings. The Classname drop-down lists implementations JMeter found, and the shipped `JavaTest` and `SleepTest` examples are useful for shaking out a plan.

code

java · 49 lines
java
package com.example.jmeter.clients;

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

public class PricingClient extends AbstractJavaSamplerClient {

    private PricingSdk sdk;

    @Override
    public Arguments getDefaultParameters() {
        Arguments args = new Arguments();
        args.addArgument("endpoint", "https://pricing.internal/v2");
        args.addArgument("sku", "${sku}");
        return args;
    }

    @Override
    public void setupTest(JavaSamplerContext context) {
        sdk = PricingSdk.connect(context.getParameter("endpoint"));
    }

    @Override
    public SampleResult runTest(JavaSamplerContext context) {
        SampleResult result = new SampleResult();
        result.setSampleLabel("quote");
        result.sampleStart();
        try {
            String body = sdk.quote(context.getParameter("sku"));
            result.setResponseData(body, "UTF-8");
            result.setResponseCodeOK();
            result.setSuccessful(true);
        } catch (Exception e) {
            result.setResponseCode("500");
            result.setResponseMessage(e.toString());
            result.setSuccessful(false);
        } finally {
            result.sampleEnd();
        }
        return result;
    }

    @Override
    public void teardownTest(JavaSamplerContext context) {
        sdk.close();
    }
}

go deeper

for a junior

Recall the interface name and its four methods, and that you normally extend AbstractJavaSamplerClient rather than implementing JavaSamplerClient directly.

for a middle

Explain the lifecycle: getDefaultParameters in the GUI, setupTest lazily before the first sample of a thread's instance, runTest per sample, teardownTest only when you override it.

for a senior

Show what a correct runTest looks like under load - timing the right window, failing loudly, and keeping per-thread state out of shared fields.

for a principal

Weigh the compiled hook against scripting for the team: a Java Request needs a build and a deployment for every change, which buys speed and reuse but adds a release cycle to test authoring.

The Java Request sampler is Apache JMeter's built-in escape hatch to compiled code: the way to make JMeter drive a client library, a proprietary protocol or an internal SDK without writing a full plugin with GUI classes, and without leaving the plan's timing, assertions and listeners behind. ## The contract Your class implements `org.apache.jmeter.protocol.java.sampler.JavaSamplerClient`, which declares exactly four methods: - **`Arguments getDefaultParameters()`** - the parameter names and default values the sampler's argument table is pre-filled with when someone picks your class in the GUI. It is documentation as much as configuration. - **`void setupTest(JavaSamplerContext context)`** - one-time preparation: build the client, open the connection pool, read a keystore. - **`SampleResult runTest(JavaSamplerContext context)`** - one sample. Everything a listener will show comes out of the `SampleResult` you return. - **`void teardownTest(JavaSamplerContext context)`** - one-time cleanup. Almost nobody implements the interface directly. `AbstractJavaSamplerClient` supplies no-op implementations plus a logger, so a real client overrides only what it needs. ## When each method actually runs This is the part candidates get wrong. `setupTest` is **not** called when the test starts; the sampler creates its client lazily and calls `setupTest` immediately before the first `runTest` on that instance. JMeter clones the test tree per thread, so each thread gets its own client object and its own `setupTest` call. `teardownTest` has a subtlety worth knowing: if a subclass of `AbstractJavaSamplerClient` does not override `teardownTest`, JMeter does not register the sampler for teardown at all and the inherited method is never called. The manual states this explicitly and gives the reason - it reduces JMeter's memory requirements. If you need cleanup, you must override the method; inheriting it is not enough. ## Writing runTest 1. Read what you need from the `JavaSamplerContext` - `getParameter(name)` and friends. Every argument arrives as a `String`, so parse and validate there. 2. Call `sampleStart()` on the `SampleResult`, do the work, call `sampleEnd()`. Anything outside that window is not measured. 3. Set `setSuccessful(true|false)`, a response code and a response message, and a sample label if you want something other than the element's name. 4. Never let an exception escape unrecorded - catch it, mark the result failed, and put the message in the response data so a listener can show it. A `runTest` that returns a result it never timed produces samples of zero elapsed time, which is a silent way to make a load test meaningless. ## How JMeter finds your class The Classname drop-down is populated by JMeter's combined lookup: implementations registered as Java services are loaded first, and then the jars on JMeter's component search path - `lib/ext` plus anything `search_paths` adds - are scanned for classes implementing `JavaSamplerClient`. Two examples ship with JMeter and always appear: `JavaTest`, useful because it lets you set values in almost every field of the result so assertions and extractors can be exercised, and `SleepTest`. If your class is missing from the list, the jar is in the wrong directory or the class is not public with a no-argument constructor; if it is in the list but errors, JMeter's log points at the `search_paths` and `plugin_dependency_paths` properties, which is usually a missing dependency rather than a missing plugin. ## Where it fits against the alternatives A Java Request is the right hook when the code is genuinely compiled and reusable: a protocol client, a signing routine that needs a real library, a workload driver you already own in Java. It costs a build and a deployment step for every change, which is its main disadvantage against JMeter's scripting elements. The JUnit Request sampler is the neighbouring hook and works differently: it scans for classes extending JUnit's `TestCase` rather than for a JMeter interface, takes no name/value parameters, and looks in `lib/junit`. Choose Java Request when you want parameters and a `SampleResult` you control; choose JUnit Request when you already have JUnit classes and want to drive them as-is.

  • Why might teardownTest never run even though your class inherits it?
    JMeter checks whether `teardownTest` is declared by a class other than `AbstractJavaSamplerClient`. If the method comes straight from the abstract base, the sampler is not registered for teardown and the inherited no-op is never invoked. Override the method in your own class if you need the cleanup to happen.
  • How does JMeter populate the Java Request Classname drop-down?
    It combines implementations registered as Java services with a scan of the component search path - `JMETER_HOME/lib/ext` plus any directories `search_paths` names - for classes implementing `JavaSamplerClient`. The shipped `JavaTest` and `SleepTest` examples always show up, which makes them a quick check that the lookup itself is working.

saying these in an interview costs you the question

  • Thinks setupTest runs once for the whole test plan
  • Returns a SampleResult without calling sampleStart and sampleEnd
  • Assumes an inherited teardownTest is always called
  • Expects typed parameters instead of Strings
  • Lets exceptions escape runTest instead of marking the result failed