Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ObjectMapper returning ClassCastException when using templated method #1914

Closed
ghost opened this issue Jan 29, 2018 · 1 comment
Closed

ObjectMapper returning ClassCastException when using templated method #1914

ghost opened this issue Jan 29, 2018 · 1 comment

Comments

@ghost
Copy link

ghost commented Jan 29, 2018

Per discussion on #921 I am reporting this bug here.

When trying to call ObjectMapper from a templated method, I receive a "ClassCastException: java.util.LinkedHashMap cannot be cast to FooClass"

This is in jackson-databind 2.8.10 in a sample project compiled via Maven.
Sample project can be found here: https://github.com/hubbazoot/object-mapper-demo

Full source code with problem:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class MainClass
{
	public static void main(String[] args) throws IOException
	{
		String json = "{\"foo\":\"bar\"}";
		FooClass firstMappedObject = thisOneWorks(json, FooClass.class);
		System.out.println("First: "+firstMappedObject);

		FooClass secondMappedObject = thisOneDoesntWork(json);
		System.out.println("Second: "+secondMappedObject);
	}

	private static <ReturnClass> ReturnClass thisOneWorks(String json, Class clazz) throws IOException
	{
		ObjectMapper objectMapper = new ObjectMapper();
		ReturnClass returnObject = objectMapper.readerFor(clazz).readValue(json);
		return returnObject;
	}

	private static <ReturnClass> ReturnClass thisOneDoesntWork(String json) throws IOException
	{
		ObjectMapper objectMapper = new ObjectMapper();
		TypeReference<ReturnClass> typeReference = new TypeReference<ReturnClass>(){};
		ReturnClass returnObject = objectMapper.readerFor(typeReference).readValue(json);
		return returnObject;
	}
}

class FooClass
{
	private String foo;

	public String getFoo()
	{
		return foo;
	}

	public void setFoo(String foo)
	{
		this.foo = foo;
	}
}
@cowtowncoder
Copy link
Member

Ah. No, this does not and can not work, due to Java Type Erasure.
You need to read about it -- there is no real type information passed with ReturnClass: you are just passing type variable ReturnClass which is not bound to anything by compiler. There must be actual Class involved somewhere.

So: you can construct JavaType or TypeReference on caller side:

TypeReference<?> ref = new TypeReference<FooClass>() { };
// or
JavaType type = mapper.constructType(FooClass.class);

and pass that. But type variables passed can not be used this way, not even via TypeReference. All it knows is that a type variable ought to be there, with bounds of ? extends Object.

There is unfortunately nothing Jackson can do about this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant