quarkusio/quarkus · error · DeploymentException

Method '%s' of class '%s' is annotated with @%s annotation w

Error message

Method '%s' of class '%s' is annotated with @%s annotation which is prohibited. Classes used as @BeanParam parameters must have a JAX-RS parameter annotation on fields only.

What it means

RESTEasy Reactive's ServerEndpointIndexer validates classes used as @BeanParam parameters during deployment. JAX-RS requires that @BeanParam classes carry JAX-RS parameter annotations (@QueryParam, @HeaderParam, etc.) on their FIELDS only; placing such an annotation on a method is prohibited, so the build step throws a DeploymentException and the application fails to start.

Source

Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/ServerEndpointIndexer.java:670

            return new PeriodParamConverter.Supplier();
        }

        throw new RuntimeException(
                contextualizeErrorMessage("Unable to handle temporal type '" + paramType + "'", currentMethodInfo));
    }

    private void validateMethodsForInjectableBean(ClassInfo currentClassInfo) {
        // do not check methods of records, they get the annotations from their record components, but that's automatic:
        // they are actually placed on the constructor parameters and also end up on the fields and methods
        if (currentClassInfo.isRecord()) {
            return;
        }
        for (MethodInfo method : currentClassInfo.methods()) {
            for (AnnotationInstance annotation : method.annotations()) {
                if (annotation.target().kind() == AnnotationTarget.Kind.METHOD) {
                    for (DotName annotationForField : JAX_RS_ANNOTATIONS_FOR_FIELDS) {
                        if (annotation.name().equals(annotationForField)) {
                            throw new DeploymentException(String.format(
                                    "Method '%s' of class '%s' is annotated with @%s annotation which is prohibited. "
                                            + "Classes used as @BeanParam parameters must have a JAX-RS parameter annotation on "
                                            + "fields only.",
                                    method.name(), currentClassInfo.name().toString(),
                                    annotation.name().withoutPackagePrefix()));
                        }
                    }
                }
            }
        }
    }

    private String contextualizeErrorMessage(String errorMessage, MethodInfo currentMethodInfo) {
        errorMessage += ". Offending method if '" + currentMethodInfo.name() + "' of class '"
                + currentMethodInfo.declaringClass().name() + "'";
        return errorMessage;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Move the JAX-RS parameter annotation from the method to the corresponding field in the @BeanParam class
  2. If annotated setters are used, annotate the field directly and leave the setter unannotated
  3. If the class is a record, annotations on components are handled automatically - consider converting to a record
  4. Remove any duplicate method-level JAX-RS parameter annotations

Example fix

// before
class MyParams {
  private String name;
  @QueryParam("name")
  public void setName(String name) { this.name = name; }
}
// after
class MyParams {
  @QueryParam("name")
  private String name;
  public void setName(String name) { this.name = name; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Check all @BeanParam classes for JAX-RS annotations on methods
for (Class<?> beanParam : beanParamClasses) {
  for (Method m : beanParam.getDeclaredMethods()) {
    for (Annotation a : m.getAnnotations()) {
      String n = a.annotationType().getName();
      if (n.startsWith("jakarta.ws.rs.") && (n.contains("Param") || n.equals("jakarta.ws.rs.core.Context")))
        throw new IllegalStateException(beanParam.getName() + " has " + n + " on method " + m.getName());
    }
  }
}

Type guard

boolean isValidBeanParam(Class<?> c) {
  return java.util.Arrays.stream(c.getDeclaredMethods())
    .flatMap(m -> java.util.Arrays.stream(m.getAnnotations()))
    .noneMatch(a -> a.annotationType().getName().matches("jakarta\\.ws\\.rs\\..*(Param|Context)"));
}

Prevention

When it happens

Trigger: A class used as a @BeanParam resource method parameter has a JAX-RS field annotation (e.g. @QueryParam, @PathParam, @HeaderParam, @CookieParam, @MatrixParam, @FormParam, @Context) placed on a setter or other method instead of (or in addition to) a field, and the class is not a record.

Common situations: Migrating legacy JAX-RS code that used annotated setters for property injection; code generated by IDEs that create getters/setters copying annotations; refactoring a @BeanParam class where annotations were accidentally moved from fields to methods.

Related errors


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