{"record":{"id":"72fa7d7f4b9e8d84","repo":"mybatis/mybatis-3","slug":"unsupported-property-type-for-cache-of-type","errorCode":null,"errorMessage":"Unsupported property type for cache: '{}' of type {}","messagePattern":"Unsupported property type for cache: '(.+?)' of type (.+?)","errorType":"validation","errorClass":"CacheException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/mapping/CacheBuilder.java","lineNumber":167,"sourceCode":"          Class<?> type = metaCache.getSetterType(name);\n          if (String.class == type) {\n            metaCache.setValue(name, value);\n          } else if (int.class == type || Integer.class == type) {\n            metaCache.setValue(name, Integer.valueOf(value));\n          } else if (long.class == type || Long.class == type) {\n            metaCache.setValue(name, Long.valueOf(value));\n          } else if (short.class == type || Short.class == type) {\n            metaCache.setValue(name, Short.valueOf(value));\n          } else if (byte.class == type || Byte.class == type) {\n            metaCache.setValue(name, Byte.valueOf(value));\n          } else if (float.class == type || Float.class == type) {\n            metaCache.setValue(name, Float.valueOf(value));\n          } else if (boolean.class == type || Boolean.class == type) {\n            metaCache.setValue(name, Boolean.valueOf(value));\n          } else if (double.class == type || Double.class == type) {\n            metaCache.setValue(name, Double.valueOf(value));\n          } else {\n            throw new CacheException(\"Unsupported property type for cache: '\" + name + \"' of type \" + type);\n          }\n        }\n      }\n    }\n    if (InitializingObject.class.isAssignableFrom(cache.getClass())) {\n      try {\n        ((InitializingObject) cache).initialize();\n      } catch (Exception e) {\n        throw new CacheException(\n            \"Failed cache initialization for '\" + cache.getId() + \"' on '\" + cache.getClass().getName() + \"'\", e);\n      }\n    }\n  }\n\n  private Cache newBaseCacheInstance(Class<? extends Cache> cacheClass, String id) {\n    Constructor<? extends Cache> cacheConstructor = getBaseCacheConstructor(cacheClass);\n    try {\n      return cacheConstructor.newInstance(id);","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/mapping/CacheBuilder.java#L149-L185","documentation":"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.","triggerScenarios":"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>.","commonSituations":"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.","solutions":["Change the cache implementation's setter to accept String and parse internally (e.g. setTimeUnit(String name) { this.unit = TimeUnit.valueOf(name); }).","Or expose an int/long setter and pass the raw value, converting internally.","If you control construction, configure the cache object before handing it to MyBatis and use <cache type> with only primitive properties."],"exampleFix":"// before\npublic class MyCache implements Cache {\n  public void setTimeUnit(TimeUnit unit) { ... } // unsupported type\n}\n\n// after\npublic class MyCache implements Cache {\n  public void setTimeUnit(String unit) { this.unit = TimeUnit.valueOf(unit); }\n}","handlingStrategy":"validation","validationCode":"// Before wiring properties, check every setter type is supported\nSet<Class<?>> supported = Set.of(String.class, int.class, Integer.class, long.class, Long.class,\n    short.class, Short.class, byte.class, Byte.class, float.class, Float.class,\n    boolean.class, Boolean.class, double.class, Double.class);\nfor (Method m : MyCache.class.getMethods()) {\n  if (m.getName().startsWith(\"set\") && m.getParameterCount() == 1\n      && !supported.contains(m.getParameterTypes()[0])) {\n    throw new IllegalStateException(\"Unsupported cache property setter: \" + m);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Expose only String/primitive setters on cache implementations meant for <property> config.","Parse richer types (enums, durations) inside String setters, not in setter signatures.","Document each supported property name and type on the custom cache class."],"tags":["mybatis","cache","configuration","reflection"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}