Repository navigation
Add generators for OptionalInt, OptionalLong and OptionalDouble #27
Description
Summary
Generators.optional(Generator<T>) covers java.util.Optional<T>, but there's no equivalent for the primitive specializations OptionalInt, OptionalLong and OptionalDouble. I'd like to propose adding them, and I'm happy to send the PR if you're open to it.
Motivation
Some APIs use the primitive optionals in their signatures, either because they're in the JDK (IntStream.max(), LongStream.findFirst(), DoubleStream.average(), …) or because they want to avoid boxing. To test them with Hegel today, you have to write the mapping by hand every time:
Generator<OptionalLong> g = oneOf(
just(OptionalLong.empty()),
longs().min(0).max(100).map(OptionalLong::of));This works, but it's boilerplate that optional(...) already handles for Optional<T>.
Also, forType / record derivation supports Optional<T> components but fails on an OptionalLong component with No default generator for java.util.OptionalLong. So a record like this can't be derived without an override:
record Stats(long count, OptionalLong max, OptionalDouble mean) {}Proposed API
In shared/src/main/java/dev/hegel/Generators.java, next to optional:
public static Generator<OptionalInt> optionalInts(Generator<Integer> generator) {
return oneOf(just(OptionalInt.empty()), generator.map(OptionalInt::of));
}
public static Generator<OptionalLong> optionalLongs(Generator<Long> generator) {
return oneOf(just(OptionalLong.empty()), generator.map(OptionalLong::of));
}
public static Generator<OptionalDouble> optionalDoubles(Generator<Double> generator) {
return oneOf(just(OptionalDouble.empty()), generator.map(OptionalDouble::of));
}Alternative: overload optional
Another option is to overload optional on the concrete generator types, so there's no new name to learn:
public static Generator<OptionalInt> optional(IntegerGenerator generator) {
return oneOf(just(OptionalInt.empty()), generator.map(OptionalInt::of));
}
public static Generator<OptionalLong> optional(LongGenerator generator) {
return oneOf(just(OptionalLong.empty()), generator.map(OptionalLong::of));
}
public static Generator<OptionalDouble> optional(DoubleGenerator generator) {
return oneOf(just(OptionalDouble.empty()), generator.map(OptionalDouble::of));
}Derivation support
In shared/src/main/java/dev/hegel/generators/Derive.java, add the three classes to scalar(...) so that forType and records support them:
if (cls == java.util.OptionalInt.class) {
return Generators.optionalInts(Generators.integers());
}
// same for OptionalLong / OptionalDoubleDoes this sound reasonable? If so, I'll go ahead with a PR. Any feedback on naming or scope is welcome.
Activity
esauro commentedon Oct 8, 2026
This proposal looks very reasonable to me. I'm looking forward to see your PR.
Add generators for OptionalInt, OptionalLong and OptionalDouble
blemale commentedon Oct 12, 2026
Here is the PR: #33