Why does this recursive generic builder pass javac, but throw a ClassCastException at runtime without any unchecked warnings?
#203831
Replies: 3 comments 1 reply
|
Without seeing the code, it's hard to pinpoint the exact issue because this behavior depends on how the recursive generic builder is declared and used. A Could you share: The builder class and its generic declaration. Those details will make it possible to explain exactly why |
|
🏷️ Discussion Type Question 💬 Feature/Topic Area Java / Compiler & Type Inference Body Hi everyone, I'm experimenting with a fluent API that relies on deeply nested Java generics, and I came across a type inference behavior that surprised me. Consider the following code: public class GenericMindmeld {
interface Wrapper<T> {
T unwrap();
}
static class Box<T> implements Wrapper<T> {
private final Object value;
Box(Object value) {
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public T unwrap() {
return (T) value;
}
}
public static <T extends Wrapper<T>> T resolve(Wrapper<?> wrapper) {
return ((Wrapper<T>) wrapper).unwrap();
}
public static void main(String[] args) {
// Compiles without warnings
String result = resolve(new Box<Box<String>>("Hello World"));
System.out.println(result);
}
}Expected behavior I expected one of the following:
Actual behavior The code compiles without any compiler warnings or errors, but it fails at runtime with: My questions are:
Any explanation of the type inference process or references to the relevant JLS sections would be greatly appreciated. Guidelines I have read and understood this category's guidelines before making this post. |
|
The root cause here isn't target-type inference misbehaving — it's that the Per JLS 4.8 and 5.1.9, once you reference a generic type through its raw form, javac disables unchecked-warning generation for member accesses/casts performed through that raw reference. That's exactly what happens with Then at the call site, This is expected (if easily-missed) JLS behavior, and it's a classic "raw type disables unchecked warnings" trap — not a compiler bug. How to make javac actually catch it:
TL;DR: it's not a javac bug — the raw |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
🏷️ Discussion Type
Question
💬 Feature/Topic Area
Java / Compiler & Type Inference
Body
Hey everyone,
I'm working on a fluent API builder using deeply nested Java generics, but I ran into a weird behavior with type inference.
Given the following code:
What I expect:
Either
javacshould rejectLine Awith a type mismatch / inference error, or it should print"Hello World".What actually happens:
It compiles without a single warning, but running it throws:
Exception in thread "main" java.lang.ClassCastException: class GenericMindmeld$Box cannot be cast to class java.lang.StringIs this an edge case bug in how
javachandles recursive bounds (T extends Wrapper<T>) against target-type inference, or is this expected behavior according to the JLS? How do I get the compiler to catch this at compile-time?Guidelines
All reactions