Generics cause ClassCastException: java.util.LinkedHashMap cannot be cast
See original GitHub issueUsing the Jackson TypeReference object and Java Generics causes a ClassCastException with the ObjectMapper’s readValue method. Specifically, the following does not work:
new TypeReference<List<MyTimeSeriesResult<R>>>(){ }
.
I have included the sample JUnit test class JacksonTypeReferenceGenericsTest, that highlights this issue.
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.junit.Test;
import junit.framework.Assert;
@SuppressWarnings( "nls" )
public class JacksonTypeReferenceGenericsTest
{
private static final ObjectMapper MAPPER = new ObjectMapper()
.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false );
private static final String SAMPLE_JSON =
"[\n" +
" {\n" +
" \"timestamp\" : \"2016-06-28T17:31:58.818+0000\",\n" +
" \"result\" : {\n" +
" \"temperature\" : 22.1,\n" +
" \"humidity\" : 64.1,\n" +
" \"wind\" : 19.1\n" +
" }\n" +
" }, {\n" +
" \"timestamp\" : \"2016-06-28T17:31:58.818+0000\",\n" +
" \"result\" : {\n" +
" \"temperature\" : 29.2,\n" +
" \"humidity\" : 40.2,\n" +
" \"wind\" : 10.2\n" +
" }\n" +
" }\n" +
"]";
@Test
public void testWithoutGenerics() throws Exception
{
List<MyTimeSeriesResult<MyWeatherResult>> resultList = getResultWithoutGenerics( SAMPLE_JSON );
Assert.assertEquals( MyTimeSeriesResult.class, resultList.get( 0 ).getClass() );
Assert.assertEquals( MyTimeSeriesResult.class, resultList.get( 1 ).getClass() );
Assert.assertEquals( MyWeatherResult.class, resultList.get( 0 ).getResult().getClass() );
Assert.assertEquals( MyWeatherResult.class, resultList.get( 1 ).getResult().getClass() );
}
private List<MyTimeSeriesResult<MyWeatherResult>> getResultWithoutGenerics( String json ) throws Exception
{
List<MyTimeSeriesResult<MyWeatherResult>> resultList =
MAPPER.readValue( json, new TypeReference<List<MyTimeSeriesResult<MyWeatherResult>>>()
{
// NO-OP
} );
return resultList;
}
@Test
public void testGenerics() throws Exception
{
List<MyTimeSeriesResult<MyWeatherResult>> resultList = getResultUsingGenerics( SAMPLE_JSON );
Assert.assertEquals( MyTimeSeriesResult.class, resultList.get( 0 ).getClass() );
Assert.assertEquals( MyTimeSeriesResult.class, resultList.get( 1 ).getClass() );
// WILL FAIL with following exception:
// java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to JacksonTypeReferenceGenericsTest$MyWeatherResult
Assert.assertEquals( MyWeatherResult.class, resultList.get( 0 ).getResult().getClass() );
Assert.assertEquals( MyWeatherResult.class, resultList.get( 1 ).getResult().getClass() );
}
private <R> List<MyTimeSeriesResult<R>> getResultUsingGenerics( String json ) throws Exception
{
List<MyTimeSeriesResult<R>> resultList =
MAPPER.readValue( json, new TypeReference<List<MyTimeSeriesResult<R>>>()
{
// NO-OP
} );
return resultList;
}
@JsonAutoDetect( fieldVisibility = JsonAutoDetect.Visibility.ANY )
@JsonIgnoreProperties( ignoreUnknown = true )
@JsonPropertyOrder( { "timestamp", "result" } )
public static class MyTimeSeriesResult<T>
{
private Date timestamp;
private T result;
public MyTimeSeriesResult()
{
//
}
public Date getTimestamp()
{
return timestamp;
}
public void setTimestamp( Date timestamp )
{
this.timestamp = timestamp;
}
public T getResult()
{
return result;
}
public void setResult( T result )
{
this.result = result;
}
}
@JsonAutoDetect( fieldVisibility = JsonAutoDetect.Visibility.ANY )
@JsonIgnoreProperties( ignoreUnknown = true )
@JsonPropertyOrder( {
"temperature", "humidity", "wind" } )
public static class MyWeatherResult
{
private Double temperature;
private Double humidity;
private Double wind;
public MyWeatherResult()
{
//
}
public Double getTemperature()
{
return temperature;
}
public void setTemperature( Double temperature )
{
this.temperature = temperature;
}
public Double getHumidity()
{
return humidity;
}
public void setHumidity( Double humidity )
{
this.humidity = humidity;
}
public Double getWind()
{
return wind;
}
public void setWind( Double wind )
{
this.wind = wind;
}
}
public static void main( String [] args ) throws Exception
{
List<MyTimeSeriesResult<MyWeatherResult>> resultList = new ArrayList<>();
final int hourToMillis = 1000 * 60 * 60;
{
MyWeatherResult myWeatherResult = new MyWeatherResult();
myWeatherResult.setTemperature( 22.1 );
myWeatherResult.setHumidity( 64.1 );
myWeatherResult.setWind( 19.1 );
MyTimeSeriesResult<MyWeatherResult> myTimeSeriesResult = new MyTimeSeriesResult<>();
myTimeSeriesResult.setTimestamp( new Date( System.currentTimeMillis() - hourToMillis * 2 ) );
myTimeSeriesResult.setResult( myWeatherResult );
resultList.add( myTimeSeriesResult );
}
{
MyWeatherResult myWeatherResult = new MyWeatherResult();
myWeatherResult.setTemperature( 29.2 );
myWeatherResult.setHumidity( 40.2 );
myWeatherResult.setWind( 10.2 );
MyTimeSeriesResult<MyWeatherResult> myTimeSeriesResult = new MyTimeSeriesResult<>();
myTimeSeriesResult.setTimestamp( new Date( System.currentTimeMillis() - hourToMillis * 2 ) );
myTimeSeriesResult.setResult( myWeatherResult );
resultList.add( myTimeSeriesResult );
}
System.out.println( MAPPER.writeValueAsString( resultList ) );
}
}
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:6 (2 by maintainers)
Top Results From Across the Web
Jackson: java.util.LinkedHashMap cannot be cast to X
Learn why the "java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to X" exception occurs and how to solve the problem.
Read more >java.util.LinkedHashMap cannot be cast to com.testing.models ...
I had a similar exception (but different problem) - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.
Read more >java.util.LinkedHashMap cannot be cast to com.testing.FeedItem
The ClassCastException thrown to indicate that your code has attempted to cast an object to a subclass of which it is not an...
Read more >How to solve "java.util.LinkedHashMap cannot be cast to java ...
This basically means that your Query is working fine, but the result cannot be displayed as a table - which is the default...
Read more >java.util.hashmap cannot be cast to java.lang.string - You.com
The issue's coming from Jackson. When it doesn't have enough information on what class to deserialize to, it uses LinkedHashMap .
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@mark1900 below is what worked for me, slightly different from yours though:
I reckon it to be suited if you use
CollectionType outer = typeFactory.constructCollectionType( ArrayList.class, inner );
rather thanJavaType outer = typeFactory.constructParametricType( ArrayList.class, inner );
This is a limitation of Java generics and specifically Type Erasure: while you may pass type variable
R
, it does not resolve to anything dynamically so this:is essentially just same as
and as a result binding will bind contents as
Map
instead of whateverR
is at compile time. Code that accesses results will however assume the type that was used (and for whichR
is expected to bind to), which is what gives cast exception.If you need to dynamically pass arbitrary types instead of static types, you have to use
TypeFactory
and construct actual types passingClass
as content type.