apache/beam · error · IllegalStateException
Subclass of SimpleFunction must override 'apply' method or…
Error message
Subclass of SimpleFunction must override 'apply' method or pass a SerializableFunction to the constructor, usually via a lambda or method reference.
What it means
SimpleFunction is a convenience subclass of DoFn that expects the subclass to override the typed 'apply(InputT)' method (or supply a SerializableFunction via constructor). In its constructor, reflection checks whether 'apply' is still the abstract base method; if so, the subclass is useless and Beam throws IllegalStateException.
Solutions
- Override the apply method in the subclass
- Pass a lambda/method reference to a MapElements.into(...).via(...) instead of subclassing SimpleFunction
- Use the SimpleFunction constructor that accepts a SerializableFunction
Example fix
// before
MapElements<String, Integer> len = MapElements.via(new SimpleFunction<String, Integer>() {});
// after
MapElements<String, Integer> len = MapElements.via(new SimpleFunction<String, Integer>() {
@Override
public Integer apply(String s) { return s.length(); }
});
// or simply:
MapElements<String, Integer> len = MapElements.into(TypeDescriptors.integers()).via(String::length); Defensive patterns
Strategy: type-guard
Validate before calling
// Prefer lambdas: MapElements.into(t).via(MyClass::apply) avoids subclassing entirely
Type guard
boolean isUsableSimpleFunction(SimpleFunction<?,?> f) {
try { return !SimpleFunction.class.getDeclaredMethod("apply", Object.class).equals(f.getClass().getMethod("apply", Object.class)); }
catch (NoSuchMethodException e) { return false; }
} Prevention
- Prefer MapElements.into(...).via(lambda) over subclassing SimpleFunction
- Never leave anonymous SimpleFunction bodies empty
- If subclassing, always override apply(InputT), not processElement
When it happens
Trigger: Declaring an anonymous or named subclass of SimpleFunction without overriding apply, e.g. new SimpleFunction<String, Integer>() {} with no body and no SerializableFunction argument.
Common situations: Copy-pasted anonymous class stubs left unimplemented; refactor removed an apply override; IDE-generated anonymous class body left empty; generics erasure confusing the developer into overriding processElement instead of apply.
Understand the failure class
Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.
Related errors
- ApproximateUnique.PerKey needs an estimation error between…
- ApproximateUnique.PerKey requires its input to use KvCoder
- Calling .triggering() to specify a trigger or calling…
- Cannot provide coder for elements of Create: For their…
- Cannot provide coder for elements of Create: For their…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4f53a0a18808d5c4.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/SimpleFunction.java:47
@SuppressWarnings({
"nullness" // TODO(https://github.com/apache/beam/issues/20497)
})
public abstract class SimpleFunction<InputT, OutputT> extends InferableFunction<InputT, OutputT>
implements SerializableFunction<InputT, OutputT> {
private final @Nullable SerializableFunction<InputT, OutputT> fn;
protected SimpleFunction() {
this.fn = null;
// A subclass must override apply if using this constructor. Check that via
// reflection.
try {
Method methodThatMustBeOverridden =
SimpleFunction.class.getDeclaredMethod("apply", Object.class);
Method methodOnSubclass = getClass().getMethod("apply", Object.class);
if (methodOnSubclass.equals(methodThatMustBeOverridden)) {
throw new IllegalStateException(
"Subclass of SimpleFunction must override 'apply' method"
+ " or pass a SerializableFunction to the constructor,"
+ " usually via a lambda or method reference.");
}
} catch (NoSuchMethodException exc) {
throw new RuntimeException("Impossible state: missing 'apply' method entirely", exc);
}
}
protected SimpleFunction(SerializableFunction<InputT, OutputT> fn) {
this.fn = fn;
}
@Override
public OutputT apply(InputT input) {
return fn.apply(input);
}View on GitHub (pinned to 12126d8942)