mybatis/mybatis-3 · error · CacheException

Unsupported property type for cache: '{}' of type {}

Error message

Unsupported property type for cache: '{}' of type {}

What it means

CacheBuilder.setCacheProperties() throws CacheException when a cache property declared in <cache ...> or CacheBuilder.properties has a setter whose type is not one of the supported ones (String, int/Integer, long/Long, short/Short, byte/Byte, float/Float, boolean/Boolean, double/Double). MyBatis reflects values as strings from XML and only converts to those primitive-ish types.

Source

Thrown at src/main/java/org/apache/ibatis/mapping/CacheBuilder.java:167

          Class<?> type = metaCache.getSetterType(name);
          if (String.class == type) {
            metaCache.setValue(name, value);
          } else if (int.class == type || Integer.class == type) {
            metaCache.setValue(name, Integer.valueOf(value));
          } else if (long.class == type || Long.class == type) {
            metaCache.setValue(name, Long.valueOf(value));
          } else if (short.class == type || Short.class == type) {
            metaCache.setValue(name, Short.valueOf(value));
          } else if (byte.class == type || Byte.class == type) {
            metaCache.setValue(name, Byte.valueOf(value));
          } else if (float.class == type || Float.class == type) {
            metaCache.setValue(name, Float.valueOf(value));
          } else if (boolean.class == type || Boolean.class == type) {
            metaCache.setValue(name, Boolean.valueOf(value));
          } else if (double.class == type || Double.class == type) {
            metaCache.setValue(name, Double.valueOf(value));
          } else {
            throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type);
          }
        }
      }
    }
    if (InitializingObject.class.isAssignableFrom(cache.getClass())) {
      try {
        ((InitializingObject) cache).initialize();
      } catch (Exception e) {
        throw new CacheException(
            "Failed cache initialization for '" + cache.getId() + "' on '" + cache.getClass().getName() + "'", e);
      }
    }
  }

  private Cache newBaseCacheInstance(Class<? extends Cache> cacheClass, String id) {
    Constructor<? extends Cache> cacheConstructor = getBaseCacheConstructor(cacheClass);
    try {
      return cacheConstructor.newInstance(id);

View on GitHub (pinned to 008069adb1)

Solutions

  1. Change the cache implementation's setter to accept String and parse internally (e.g. setTimeUnit(String name) { this.unit = TimeUnit.valueOf(name); }).
  2. Or expose an int/long setter and pass the raw value, converting internally.
  3. If you control construction, configure the cache object before handing it to MyBatis and use <cache type> with only primitive properties.

Example fix

// before
public class MyCache implements Cache {
  public void setTimeUnit(TimeUnit unit) { ... } // unsupported type
}

// after
public class MyCache implements Cache {
  public void setTimeUnit(String unit) { this.unit = TimeUnit.valueOf(unit); }
}
Defensive patterns

Strategy: validation

Validate before calling

// Before wiring properties, check every setter type is supported
Set<Class<?>> supported = Set.of(String.class, int.class, Integer.class, long.class, Long.class,
    short.class, Short.class, byte.class, Byte.class, float.class, Float.class,
    boolean.class, Boolean.class, double.class, Double.class);
for (Method m : MyCache.class.getMethods()) {
  if (m.getName().startsWith("set") && m.getParameterCount() == 1
      && !supported.contains(m.getParameterTypes()[0])) {
    throw new IllegalStateException("Unsupported cache property setter: " + m);
  }
}

Prevention

When it happens

Trigger: Configuring a custom cache with a property whose setter takes another type, e.g. setTimeUnit(TimeUnit), setMemoryLimit(BigDecimal), or an enum setter, via <cache type="com.x.MyCache"><property name="timeUnit" value="SECONDS"/></cache>.

Common situations: Adapting third-party caches (Infinispan, Hazelcast, custom) to MyBatis where configuration setters naturally use richer types than primitives; copying config from another framework that supports typed properties.

Related errors


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