2 min read

Java 11 - ParameterizedTypeReference issue

#java11 #bug

It's not everyday when you run into a Java bug.🪲

Brief

Let's say we wanted to interact with a third-party service which returned data in the follow structure:

{
	"metadata": "Car list",
	"data": [
    		{"name": "Honda"},
		{"name": "Mazda"}
	]
}
GET /v1/cars
{
	"metadata": "Motorcycle list",
	"data": [
    		{"type": "Kawasaki"},
		{"type": "Suzuki"}
	]
}
GET /v1/motorcycles

Implementation

First, we need to define the payload structure. We'll take the generic route and define the models this way:

public class Car {
	private String name;
}

public class Motorcycle {
	private String type;
}
public class MetadataObject<T> {
	private String metadata;
	private List<T> data;
}

For simplicity purposes we'll use Spring's  RestTemplate to send the HTTP requests to the external service.

public class IntegrationClient {
	RestTemplate restTemplate = new RestTemplate();
    
    public Metadata<Car> getCars() {
    	String url = ...
    	ResponseEntity<MetadataObject<Car>> response =  restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<MetadataObject<Car>>(){});
        return response.getBody();
    }
    
     public Metadata<Motorcycle> getMotorcycles() {
    	String url = ...
    	ResponseEntity<MetadataObject<Motorcycle>> response =  restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<MetadataObject<Motorcycle>>(){});
        return response.getBody();
    }
    
}

At this point, IntelliJ already suggested that I could drop the explicit generic type for ParameterizedTypeReference because he's smart enough to infer it. So, as to many other times when IntelliJ suggestions came to help, I did just that.

ResponseEntity<MetadataObject<Car>> response =  restTemplate.exchange(url, new ParameterizedTypeReference<MetadataObject<Car>>(){});

became

ResponseEntity<MetadataObject<Car>> response =  restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<>(){});

All good and well, until I wanted to run the application.

compiler message file broken: key=compiler.misc.msg.bug arguments=11.0.2, {1}, {2}, {3}, {4}, {5}, {6}, {7} java.lang.NullPointerException at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitApply(Flow.java:1235) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1634) at jdk.compiler/com.sun.tools.javac.tree.TreeScanner.scan(TreeScanner.java:49) at jdk.compiler/com.sun.tools.javac.comp.Flow$BaseAnalyzer.scan(Flow.java:398) at jdk.compiler/com.sun.tools.javac.comp.Flow$FlowAnalyzer.visitVarDef(Flow.java:989)

Didn't really understand what was the issue but after some Googling and Stackoverflowing I found out that this is actually a JDK bug 😱 .

The problem seems to be that when compiling the code, Java couldn't infer the arguments for the ParameterizedTypeReference.

It got fixed in JDK 12 and also been backported al the way to JDK 11.0.4 .

Conclusion

If you find yourself in the same situation as me, you either keep the type between the diamond signs or even better, think about upgrading your JDK version, it's 2022 already..


💡
Don't miss out on more posts like this! Susbcribe to our free newsletter!
💡
Currently I am working on a Java Interview e-book designed to successfully get you through any Java technical interview you may take.
Stay tuned! 🚀