{"record":{"id":"22755954dee2d4ae","repo":"mybatis/mybatis-3","slug":"extends-typereference-but-misses-the-type-par","errorCode":null,"errorMessage":"'{}' extends TypeReference but misses the type parameter. Remove the extension or add a type parameter to it.","messagePattern":"'(.+?)' extends TypeReference but misses the type parameter\\. Remove the extension or add a type parameter to it\\.","errorType":"exception","errorClass":"TypeException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/type/TypeReference.java","lineNumber":47,"sourceCode":" * @author Simone Tripodi\n */\npublic abstract class TypeReference<T> {\n\n  private final Type rawType;\n\n  protected TypeReference() {\n    rawType = getSuperclassTypeParameter(getClass());\n  }\n\n  Type getSuperclassTypeParameter(Class<?> clazz) {\n    Type genericSuperclass = clazz.getGenericSuperclass();\n    if (genericSuperclass instanceof Class) {\n      // try to climb up the hierarchy until meet something useful\n      if (TypeReference.class != genericSuperclass) {\n        return getSuperclassTypeParameter(clazz.getSuperclass());\n      }\n\n      throw new TypeException(\"'\" + getClass() + \"' extends TypeReference but misses the type parameter. \"\n          + \"Remove the extension or add a type parameter to it.\");\n    }\n\n    return ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];\n  }\n\n  public final Type getRawType() {\n    return rawType;\n  }\n\n  @Override\n  public String toString() {\n    return rawType.toString();\n  }\n\n}\n","sourceCodeStart":29,"sourceCodeEnd":64,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/type/TypeReference.java#L29-L64","documentation":"TypeReference captures its generic type by walking the superclass chain to find a ParameterizedType. If the chain bottoms out at TypeReference itself without ever passing through a parameterized declaration (a raw subclass like 'class Foo extends TypeReference'), the type argument cannot be captured and this TypeException names the offending class.","triggerScenarios":"Declaring a raw subclass: class MyHandler extends TypeReference (no <T>); extending a raw intermediate class (class Middle extends TypeReference, then class MyHandler extends Middle); using the handler in a mapper before any type info is resolvable.","commonSituations":"Copy-pasting BaseTypeHandler subclasses that extend TypeReference-backed bases without adding the type parameter; legacy pre-generics code compiled with raw types after a library upgrade introduced TypeReference.","solutions":["Add the type parameter: class MyHandler extends TypeReference<String>","Parameterize every intermediate class in the hierarchy, not just the leaf","If the base extension is accidental (you did not need TypeReference), remove it and implement TypeHandler directly"],"exampleFix":"// before\npublic class IdRef extends TypeReference { } // raw\n\n// after\npublic class IdRef extends TypeReference<Long> { }","handlingStrategy":"validation","validationCode":"void checkTypeReference(Class<?> c) {\n  Type sup = c.getGenericSuperclass();\n  if (sup instanceof Class && sup == TypeReference.class) {\n    throw new IllegalStateException(c.getName() + \" extends TypeReference raw — add a type parameter\");\n  }\n}","typeGuard":"static boolean isParameterizedTypeReference(Class<?> c) {\n  return c.getGenericSuperclass() instanceof ParameterizedType;\n}","tryCatchPattern":null,"preventionTips":["Never extend TypeReference raw — always supply <T>","Parameterize every intermediate class in handler hierarchies","Enable -Xlint:raw-types and treat raw-type warnings as errors in handler code"],"tags":["mybatis","generics","type-reference","type-handler"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}