mybatis/mybatis-3 · error · BuilderException

Cannot use both value() and name() attribute in the @CacheNa

Error message

Cannot use both value() and name() attribute in the @CacheNamespaceRef

What it means

The sibling check in parseCacheRef(): @CacheNamespaceRef has both value() set (non-void class) and a non-empty name() string. The two attributes are alternative ways to identify the referenced namespace; specifying both is ambiguous and rejected.

Source

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

      return null;
    }
    Properties props = new Properties();
    for (Property property : properties) {
      props.setProperty(property.name(), PropertyParser.parse(property.value(), configuration.getVariables()));
    }
    return props;
  }

  private void parseCacheRef() {
    CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class);
    if (cacheDomainRef != null) {
      Class<?> refType = cacheDomainRef.value();
      String refName = cacheDomainRef.name();
      if (refType == void.class && refName.isEmpty()) {
        throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef");
      }
      if (refType != void.class && !refName.isEmpty()) {
        throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");
      }
      String namespace = refType != void.class ? refType.getName() : refName;
      try {
        assistant.useCacheRef(namespace);
      } catch (IncompleteElementException e) {
        configuration.addIncompleteCacheRef(new CacheRefResolver(assistant, namespace));
      }
    }
  }

  private String parseResultMap(Method method) {
    Class<?> returnType = getReturnType(method, type);
    Arg[] args = method.getAnnotationsByType(Arg.class);
    Result[] results = method.getAnnotationsByType(Result.class);
    TypeDiscriminator typeDiscriminator = method.getAnnotation(TypeDiscriminator.class);
    String resultMapId = generateResultMapName(method);
    applyResultMap(resultMapId, returnType, args, results, typeDiscriminator);
    return resultMapId;

View on GitHub (pinned to 008069adb1)

Solutions

  1. Keep exactly one attribute: either @CacheNamespaceRef(UserMapper.class) or @CacheNamespaceRef(name = "com.acme.UserMapper")
  2. Prefer the class form (value) so refactors stay compile-safe

Example fix

// before
@CacheNamespaceRef(value = UserMapper.class, name = "com.acme.UserMapper")
// after
@CacheNamespaceRef(UserMapper.class)
Defensive patterns

Strategy: type-guard

Type guard

for (Class<?> mapper : scannedMappers) {
  CacheNamespaceRef r = mapper.getAnnotation(CacheNamespaceRef.class);
  if (r != null && r.value() != void.class && !r.name().isEmpty()) {
    throw new IllegalStateException(mapper + " sets both value() and name() in @CacheNamespaceRef");
  }
}

Prevention

When it happens

Trigger: @CacheNamespaceRef(value = UserMapper.class, name = "com.acme.UserMapper") — both attributes populated.

Common situations: Copy-paste or IDE auto-complete filling both; refactoring from name-based to class-based refs without deleting the old attribute.

Related errors


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