quarkusio/quarkus · error · IllegalArgumentException

Class '{biFunctionClassInfo.name}' must contain a no-args co

Error message

Class '{biFunctionClassInfo.name}' must contain a no-args constructor

What it means

The @CustomSerialization annotation on a REST resource (class or method) names a class implementing BiFunction that performs custom JSON serialization. Because Quarkus instantiates this class reflectively at runtime, it must have a public no-argument constructor. During the build, if the Jandex index can resolve the class and it lacks a no-args constructor, the deployment fails with this IllegalArgumentException.

Source

Thrown at extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/ResteasyReactiveJacksonProcessor.java:299

                }
            }
            if (resourceClass.annotationsMap().containsKey(CUSTOM_SERIALIZATION)) {
                jacksonFeatures.add(JacksonFeatureBuildItem.Feature.CUSTOM_SERIALIZATION);
                for (AnnotationInstance instance : resourceClass.annotationsMap().get(CUSTOM_SERIALIZATION)) {
                    AnnotationValue annotationValue = instance.value();
                    if (annotationValue == null) {
                        continue;
                    }
                    Type biFunctionType = annotationValue.asClass();
                    if (biFunctionType == null) {
                        continue;
                    }
                    ClassInfo biFunctionClassInfo = index.getIndex().getClassByName(biFunctionType.name());
                    if (biFunctionClassInfo == null) {
                        // be lenient
                    } else {
                        if (!biFunctionClassInfo.hasNoArgsConstructor()) {
                            throw new IllegalArgumentException(
                                    "Class '" + biFunctionClassInfo.name() + "' must contain a no-args constructor");
                        }
                    }
                    reflectiveClassProducer.produce(
                            ReflectiveClassBuildItem.builder(biFunctionType.name().toString())
                                    .reason(getClass().getName())
                                    .build());
                    recorder.recordCustomSerialization(getTargetId(instance), biFunctionType.name().toString());
                }
            }
            if (resourceClass.annotationsMap().containsKey(CUSTOM_DESERIALIZATION)) {
                jacksonFeatures.add(JacksonFeatureBuildItem.Feature.CUSTOM_DESERIALIZATION);
                for (AnnotationInstance instance : resourceClass.annotationsMap().get(CUSTOM_DESERIALIZATION)) {
                    AnnotationValue annotationValue = instance.value();
                    if (annotationValue == null) {
                        continue;
                    }
                    Type biFunctionType = annotationValue.asClass();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a public no-argument constructor to the BiFunction class named in the message
  2. Move required dependencies into the apply(...) call or use static configuration instead of constructor injection
  3. Make the class a static nested class or top-level class with an explicit no-arg constructor
  4. Verify the class actually implements BiFunction<Object, ObjectMapper, Object> (or the deserialization equivalent) with a stateless design

Example fix

// before
class MySerializer implements BiFunction<Object, ObjectMapper, Object> {
    private final ObjectMapper mapper;
    MySerializer(ObjectMapper m) { this.mapper = m; }
}

// after
class MySerializer implements BiFunction<Object, ObjectMapper, Object> {
    public MySerializer() { }
    @Override
    public Object apply(Object value, ObjectMapper mapper) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = MySerializer.class;
try {
    c.getDeclaredConstructor().setAccessible(true);
    c.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException e) {
    throw new IllegalArgumentException("@CustomSerialization class " + c.getName() + " needs a public no-args constructor");
}

Type guard

static boolean hasNoArgsConstructor(Class<?> c) {
    try { c.getDeclaredConstructor(); return true; }
    catch (NoSuchMethodException e) { return false; }
}

Try / catch

try {
    deploy();
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("must contain a no-args constructor")) {
        // fix the serializer class named in the message
    }
}

Prevention

When it happens

Trigger: Annotating a resource with @CustomSerialization(value = MyBiFunction.class) where MyBiFunction only has parameterized constructors (e.g. takes ObjectMapper or config in its constructor).

Common situations: Writing the custom serializer as an inner class capturing outer state; adding constructor injection to an existing BiFunction serializer; copying a Spring-style bean pattern where constructor args are expected.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/42aaff388149c68b. Report an issue: GitHub.