{"record":{"id":"93e1323b1715cce0","repo":"mybatis/mybatis-3","slug":"if-there-is-no-type-discriminator-then-the-namedr","errorCode":null,"errorMessage":"If there is no type discriminator, then the NamedResultMap annotation requires at least one constructor argument or property mapping","messagePattern":"If there is no type discriminator, then the NamedResultMap annotation requires at least one constructor argument or property mapping","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java","lineNumber":266,"sourceCode":"    String resultMapId = type.getName() + '.' + namedResultMap.id();\n    Class<?> returnType = namedResultMap.javaType();\n    Arg[] args = namedResultMap.constructorArguments();\n    Result[] results = namedResultMap.propertyMappings();\n    TypeDiscriminator typeDiscriminator = namedResultMap.typeDiscriminator();\n    if (AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(typeDiscriminator.column())) {\n      typeDiscriminator = null;\n    }\n\n    applyResultMap(resultMapId, returnType, args, results, typeDiscriminator);\n  }\n\n  private void validateNamedResultMap(NamedResultMap namedResultMap) {\n    if (!AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(namedResultMap.typeDiscriminator().column())) {\n      return;\n    }\n\n    if (namedResultMap.constructorArguments().length == 0 && namedResultMap.propertyMappings().length == 0) {\n      throw new BuilderException(\"If there is no type discriminator, then the NamedResultMap annotation \"\n          + \"requires at least one constructor argument or property mapping\");\n    }\n  }\n\n  private String generateResultMapName(Method method) {\n    Results results = method.getAnnotation(Results.class);\n    if (results != null && !results.id().isEmpty()) {\n      return type.getName() + \".\" + results.id();\n    }\n    StringBuilder suffix = new StringBuilder();\n    for (Class<?> c : method.getParameterTypes()) {\n      suffix.append(\"-\");\n      suffix.append(c.getSimpleName());\n    }\n    if (suffix.length() < 1) {\n      suffix.append(\"-void\");\n    }\n    return type.getName() + \".\" + method.getName() + suffix;","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java#L248-L284","documentation":"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.","triggerScenarios":"@NamedResultMap(id = \"userMap\") with empty constructorArguments, propertyMappings, and typeDiscriminator defaulting to the NULL discriminator column.","commonSituations":"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.","solutions":["Add at least one @Arg in constructorArguments or @Property in propertyMappings to the @NamedResultMap","Or add a typeDiscriminator so the map routes among subtypes","If you only wanted automapping by resultType, drop @NamedResultMap entirely and use resultType on the statement"],"exampleFix":"// before\n@NamedResultMap(id = \"userMap\")\n// after\n@NamedResultMap(id = \"userMap\", propertyMappings = @Property(column = \"user_name\", property = \"userName\"))","handlingStrategy":"validation","validationCode":"for (Method m : mapper.getMethods()) {\n  NamedResultMap nrm = m.getAnnotation(NamedResultMap.class);\n  if (nrm != null && nrm.constructorArguments().length == 0\n      && nrm.propertyMappings().length == 0\n      && \"@null@\".equals(nrm.typeDiscriminator().column())) { /* default sentinel */\n    throw new IllegalStateException(m + \" has empty @NamedResultMap\");\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only add @NamedResultMap when mappings are ready; otherwise use resultType automapping","Add a config-load test that instantiates all mapper annotations in CI"],"tags":["mybatis","annotation","resultmap","configuration"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}