{"record":{"id":"4482c3ed83db016f","repo":"apple/pkl","slug":"javatype-token-must-be-parameterized","errorCode":null,"errorMessage":"JavaType token must be parameterized.","messagePattern":"JavaType token must be parameterized\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"pkl-config-java/src/main/java/org/pkl/config/java/JavaType.java","lineNumber":100,"sourceCode":" */\npublic class JavaType<T> {\n  private final Type type;\n\n  /**\n   * Constructs a {@code JavaType} using the super-type token idiom.\n   *\n   * <p>Subclasses must be parameterized with the desired type, for example:\n   *\n   * <pre>{@code\n   * new JavaType<List<@Nullable String>>() {}\n   * }</pre>\n   *\n   * @throws IllegalStateException if this instance is not parameterized\n   */\n  protected JavaType() {\n    var superclass = getClass().getGenericSuperclass();\n    if (!(superclass instanceof ParameterizedType parameterizedType)) {\n      throw new IllegalStateException(\"JavaType token must be parameterized.\");\n    }\n    type = parameterizedType.getActualTypeArguments()[0];\n  }\n\n  private JavaType(Type type) {\n    this.type = type;\n  }\n\n  /** Creates a {@code JavaType} for the given type. */\n  public static <T> JavaType<T> of(Class<T> type) {\n    return new JavaType<>(type);\n  }\n\n  /**\n   * Creates a {@code JavaType} for the given {@link Type}.\n   *\n   * <p>Use this method when the target type is already available as a {@link Type}; otherwise,\n   * prefer {@link #of(Class)}.","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-config-java/src/main/java/org/pkl/config/java/JavaType.java#L82-L118","documentation":"JavaType<T> is a super-type-token: the protected no-arg constructor captures T via the concrete subclass's generic superclass. It throws IllegalStateException when the class using it is not a parameterized subclass (raw JavaType or non-generic subclass), because then there is no TypeArgument to capture into the type field.","triggerScenarios":"Instantiating JavaType anonymously or as a subclass without a type argument, e.g. new JavaType() {...} instead of new JavaType<Map<String, String>>() {}, or referencing JavaType.class directly as a raw type.","commonSituations":"Copy-pasting a JavaType snippet but dropping the diamond type argument; using JavaType with a type variable erased at runtime; building a generic helper that instantiates new JavaType<T>() where T is not reified by a subclass.","solutions":["Instantiate as a parameterized anonymous subclass: new JavaType<List<String>>() {}.","If you already have a java.lang.reflect.Type, use the private/alternative constructor path or mapper APIs that accept a Type directly instead of the token.","Never write raw new JavaType(); always supply the generic argument."],"exampleFix":"// before\nJavaType type = new JavaType<>() {}; // raw target, no reified argument\n// after\nJavaType<Map<String, String>> type = new JavaType<Map<String, String>>() {};","handlingStrategy":"type-guard","validationCode":"// ensure the token class carries a reified type argument\nstatic <T> JavaType<T> token(Class<? extends JavaType<T>> impl) {\n  return java.lang.reflect.Modifier.isAbstract(impl.getModifiers())\n      ? fail(\"JavaType subclass must be concrete and parameterized\")\n      : instantiate(impl);\n}","typeGuard":"static boolean isParameterized(JavaType<?> t) {\n  return t.getClass().getGenericSuperclass() instanceof ParameterizedType pt\n      && pt.getActualTypeArguments()[0] instanceof Class<?>;\n}","tryCatchPattern":"try {\n  JavaType<List<String>> t = new JavaType<List<String>>() {};\n  return mapper.map(value, t);\n} catch (IllegalStateException e) {\n  throw new IllegalArgumentException(\"Use new JavaType<T>() {} with an explicit type\", e);\n}","preventionTips":["Always instantiate JavaType as a parameterized anonymous subclass: new JavaType<Map<K,V>>() {}","Never use the raw type new JavaType() or new JavaType<>() assigned to a raw variable","For dynamically-known types, prefer mapper APIs that accept java.lang.reflect.Type","Store shared tokens as static final constants so the pattern is copied correctly"],"tags":["generics","super-type-token","reflection","java","pkl"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}