{"record":{"id":"6cbd02ad94c5dc26","repo":"mybatis/mybatis-3","slug":"does-not-implement-typehandler","errorCode":null,"errorMessage":"'{}' does not implement TypeHandler.","messagePattern":"'(.+?)' does not implement TypeHandler\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java","lineNumber":467,"sourceCode":"\n  @Deprecated(since = \"3.6.0\", forRemoval = true)\n  public void register(String javaTypeClassName, String typeHandlerClassName) throws ClassNotFoundException {\n    register(Resources.classForName(javaTypeClassName), Resources.classForName(typeHandlerClassName));\n  }\n\n  public void register(Type mappedJavaType, Class<?> handlerClass) {\n    register(new Type[] { mappedJavaType }, mappedJdbcTypes(handlerClass), handlerClass);\n  }\n\n  // java type + jdbc type + handler type\n\n  public void register(Type mappedJavaType, JdbcType mappedJdbcType, Class<?> handlerClass) {\n    register(new Type[] { mappedJavaType }, new JdbcType[] { mappedJdbcType }, handlerClass);\n  }\n\n  private void register(Type[] mappedJavaTypes, JdbcType[] mappedJdbcTypes, Class<?> handlerClass) {\n    if (!TypeHandler.class.isAssignableFrom(handlerClass)) {\n      throw new IllegalArgumentException(String.format(\"'%s' does not implement TypeHandler.\", handlerClass.getName()));\n    }\n    for (Constructor<?> constructor : handlerClass.getConstructors()) {\n      if (constructor.getParameterCount() != 1) {\n        continue;\n      }\n      Class<?> argType = constructor.getParameterTypes()[0];\n      if (Type.class.equals(argType) || Class.class.equals(argType)) {\n        for (Type javaType : mappedJavaTypes) {\n          smartHandlers.computeIfAbsent(javaType, k -> constructor);\n        }\n        return;\n      }\n    }\n    // It is not a smart handler\n    register(mappedJavaTypes, mappedJdbcTypes, getInstance(null, handlerClass));\n  }\n\n  private Type[] mappedJavaTypes(Class<?> clazz) {","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java#L449-L485","documentation":"Before scanning a handler class's constructors, TypeHandlerRegistry.register verifies TypeHandler.class.isAssignableFrom(handlerClass). A class that does not implement the interface is rejected immediately with this IllegalArgumentException naming the class.","triggerScenarios":"<typeHandler handler=\"com.example.NotAHandler\"/> where the class is a plain utility/mapper class; passing a type-alias-resolved class that points to the wrong type; copy-paste of a handler registration with an outdated class name.","commonSituations":"Refactoring that renamed the real handler and left an old class in place; alias collisions resolving handler= to a different class; pointing handler= at an interceptor (org.apache.ibatis.plugin.Interceptor) instead of a TypeHandler.","solutions":["Make the class implement org.apache.ibatis.type.TypeHandler (usually by extending BaseTypeHandler<T>)","Fix the handler attribute to reference the actual handler class","If an alias is used for the handler, verify it resolves to the intended class"],"exampleFix":"// before\npublic class MoneyMapper { ... }\n\n// after\npublic class MoneyTypeHandler extends BaseTypeHandler<Money> { ... }","handlingStrategy":"type-guard","validationCode":"if (!TypeHandler.class.isAssignableFrom(handlerClass)) {\n  throw new IllegalArgumentException(handlerClass.getName() + \" is not a TypeHandler\");\n}","typeGuard":"static boolean isTypeHandler(Class<?> c) {\n  return c != null && TypeHandler.class.isAssignableFrom(c);\n}","tryCatchPattern":null,"preventionTips":["Make handlers extend BaseTypeHandler<T> so the interface is guaranteed","CI check: every class named in handler= implements TypeHandler"],"tags":["mybatis","type-handler","registration","interface"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}