mybatis/mybatis-3 · error · BuilderException

If there is no type discriminator, then the NamedResultMap a

Error message

If there is no type discriminator, then the NamedResultMap annotation requires at least one constructor argument or property mapping

What it means

Thrown by MapperAnnotationBuilder.validateNamedResultMap(): a @NamedResultMap annotation declares neither a type discriminator nor any constructorArguments() nor propertyMappings(). Without at least one mapping (or a discriminator to route types), the named result map would carry no column-to-property information and is rejected as a configuration error.

Source

Thrown at src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java:266

    String resultMapId = type.getName() + '.' + namedResultMap.id();
    Class<?> returnType = namedResultMap.javaType();
    Arg[] args = namedResultMap.constructorArguments();
    Result[] results = namedResultMap.propertyMappings();
    TypeDiscriminator typeDiscriminator = namedResultMap.typeDiscriminator();
    if (AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(typeDiscriminator.column())) {
      typeDiscriminator = null;
    }

    applyResultMap(resultMapId, returnType, args, results, typeDiscriminator);
  }

  private void validateNamedResultMap(NamedResultMap namedResultMap) {
    if (!AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(namedResultMap.typeDiscriminator().column())) {
      return;
    }

    if (namedResultMap.constructorArguments().length == 0 && namedResultMap.propertyMappings().length == 0) {
      throw new BuilderException("If there is no type discriminator, then the NamedResultMap annotation "
          + "requires at least one constructor argument or property mapping");
    }
  }

  private String generateResultMapName(Method method) {
    Results results = method.getAnnotation(Results.class);
    if (results != null && !results.id().isEmpty()) {
      return type.getName() + "." + results.id();
    }
    StringBuilder suffix = new StringBuilder();
    for (Class<?> c : method.getParameterTypes()) {
      suffix.append("-");
      suffix.append(c.getSimpleName());
    }
    if (suffix.length() < 1) {
      suffix.append("-void");
    }
    return type.getName() + "." + method.getName() + suffix;

View on GitHub (pinned to 008069adb1)

Solutions

  1. Add at least one @Arg in constructorArguments or @Property in propertyMappings to the @NamedResultMap
  2. Or add a typeDiscriminator so the map routes among subtypes
  3. If you only wanted automapping by resultType, drop @NamedResultMap entirely and use resultType on the statement

Example fix

// before
@NamedResultMap(id = "userMap")
// after
@NamedResultMap(id = "userMap", propertyMappings = @Property(column = "user_name", property = "userName"))
Defensive patterns

Strategy: validation

Validate before calling

for (Method m : mapper.getMethods()) {
  NamedResultMap nrm = m.getAnnotation(NamedResultMap.class);
  if (nrm != null && nrm.constructorArguments().length == 0
      && nrm.propertyMappings().length == 0
      && "@null@".equals(nrm.typeDiscriminator().column())) { /* default sentinel */
    throw new IllegalStateException(m + " has empty @NamedResultMap");
  }
}

Prevention

When it happens

Trigger: @NamedResultMap(id = "userMap") with empty constructorArguments, propertyMappings, and typeDiscriminator defaulting to the NULL discriminator column.

Common situations: Adding @NamedResultMap intending to reuse it via @ResultMap before filling in mappings; misunderstanding that the annotation requires explicit mappings (unlike automapping); leftover stub annotation after removing mappings.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/93e1323b1715cce0. Report an issue: GitHub.