Is your feature request related to a problem? Please describe.

Currently to deserialize object in ObjectMapper we use below syntax -

ObjectMapper m = new ObjectMapper();
final String JSON = "{ \"x\" : 3 }";

Bean bean = m.readValue(JSON, Bean.class);

Can ObjectMapper automatically detect the class to be deserialized based on the return type?

This is already implemented in Mockito https://github.com/mockito/mockito/pull/2779

Describe the solution you'd like

Below method can be added in ObjectMapper class to detect class automatically.

    public <T> T readValue(String content, T... reified) throws JsonProcessingException {
        if (reified.length > 0) {
            throw new IllegalArgumentException("Please don't pass any values here. Java will detect class automatically.");
        }
        return readValue(content, _typeFactory.constructType(getClassOf(reified)));
    }

Usage example

ObjectMapper m = new ObjectMapper();
final String JSON = "{ \"x\" : 3 }";

Bean bean = m.readValue(JSON);

Additional context

No response

Comment From: rohanlopes20

https://github.com/rohanlopes20/jackson-databind-auto-detect-class

Created this fork for same.

Comment From: pjfanning

For me, this looks potentially useful.

Don't change yet but it might be better to target master branch instead of 2.19 branch. The master branch uses different package names (tools.jackson instead of com.fasterxml.jackson).

The tests need to be improved. Assert the values in the bean not just that it isn't null. More tests needed too.

Comment From: pjfanning

@cowtowncoder most of the code is copied from a Mockito PR. This has licensing implications. In the ASF, we would require that the LICENSE file is updated to include the MIT license from Mockito. Something along the licenses of saying that source file X has code copied from Mockito under the MIT License and then paste in the license.

Comment From: cowtowncoder

Hmmh. The last thing I want to import are license hassles. MIT is more permissive so it should be ok but... I guess as long as PR contains changes.

Also: same auto-detection should be, I think, added to ObjectReader.

Comment From: cowtowncoder

Forgot to mention: yes, if this works without adding complications for existing overloads, this seems like a very nice ergonomic improvement.

Comment From: JooHyukKim

Good one! Like we have in Kotlin extension. Just some related article about this reified Generics in case anyone curious.

Comment From: JooHyukKim

FYI, we have several readValue methods that we can apply this solution.

Comment From: JooHyukKim

@rohanlopes20 Just wondering, are you planning on contributing? :))) Seems like you almost have it.

Comment From: rohanlopes20

Yes, I am checking reader code based on above comment. I saw some methods which can use this but seems like there are no test cases for same.

Also, can you let me know what else is required in tests other than checking not null objects? @cowtowncoder @JooHyukKim

Comment From: rohanlopes20

@cowtowncoder Saw ObjectReader code, not sure if my understanding is correct but below 1st method is public.

    public <T> T readValue(InputStream src) throws IOException
    {
        if (_dataFormatReaders != null) {
            return (T) _detectBindAndClose(_dataFormatReaders.findFormat(src), false);
        }
        return (T) _bindAndClose(_considerFilter(createParser(src), false));
    }

    public <T> T readValue(InputStream src, Class<T> valueType) throws IOException
    {
        return (T) forType(valueType).readValue(src);
    }

If below code added to handle autodetection then it directly refers to code block above(1st method ObjectReader#readValue(InputStream src) instead of reified code. In this case we have to make it private. Pretty sure that is incorrect(testSerializeAsExternalizable this test fails too).

    public <T> T readValue(InputStream src, T... reified) throws IOException
    {
        return forType(getClassOf(reified)).readValue(src);
    }

Can you please guide what needs to be done ? Don't want to break jackson standards. You can commit in fork if required. https://github.com/rohanlopes20/jackson-databind-auto-detect-class

@cowtowncoder @JooHyukKim

Comment From: JooHyukKim

Can you please guide what needs to be done ? Don't want to break jackson standards. You can commit in fork if required. https://github.com/rohanlopes20/jackson-databind-auto-detect-class

If we do this for Jackson 3, we could just remove the existing public <T> T readValue(InputStream src) method? That's only if our new reified (InputStream src, T... reified) method wouldn't break any performance/implementation.

Comment From: rohanlopes20

I did that but it broke test case testSerializeAsExternalizable.

Comment From: JooHyukKim

And where is the failing test result? Let's write a PR so we can all see what's going on

Comment From: rohanlopes20

https://github.com/FasterXML/jackson-databind/pull/5071

org.opentest4j.AssertionFailedError: Expected :com.fasterxml.jackson.databind.interop.TestExternalizable$MyPojo@56a6d5a6 Actual :com.fasterxml.jackson.databind.interop.TestExternalizable$MyPojo@55740540

@JooHyukKim

Comment From: cowtowncoder

Ahhh. I forgot the basic thing about ObjectReader -- right we do not actually want to do similar overloads: the idea is that ObjectReader is constructed with/for target type, so readValue() methods do not take target type. There was later addition of readValue() with target type, for 2.x: I now wish I had not accepted that PR. These are removed from 3.0.

So I think type detection wrt ObjectReader should only be done, possibly, for constructing ObjectReader instances -- but not 100% that is doable. That is, only for ObjectMapper methods of form:

public ObjectReader readerFor(JavaType type)

then something like

public <T> ObjectReader readerFor(T... reified)

if that is possible -- and importantly, if that is actually usable from caller perspective.

Does this make more sense?

Comment From: rohanlopes20

If that is the case then will revert changes for other readValue methods.

For above case below works -

public <T> ObjectReader readerFor(T... reified) {
        // Detect class type
        Class<T> clazz = getClassOf(reified);

        // Convert class to JavaType
        JavaType valueType = _config.getTypeFactory().constructType(clazz);

        return forType(valueType);
    }

Test Case

   @Test
    public void testAutoDetectForReader() throws Exception
    {
        Number n = MAPPER.reader().readerFor().readValue("123 ");
        assertEquals(Integer.valueOf(123), n);
    }

Comment From: rohanlopes20

@cowtowncoder @JooHyukKim Can you check and revert please.

Comment From: cowtowncoder

I think that if we do that it should be:

  1. Only for 3.0 (or 3.x in general) AND
  2. Use new method names, not overloading existing ones AND
  3. We'd need to move quickly -- last 3.0.0-rc needed in 1-2 weeks.

Comment From: rohanlopes20

@cowtowncoder can you let me know branch to be used?

https://github.com/FasterXML/jackson-databind/tree/jackson-databind-3.0.0-rc9

or

https://github.com/FasterXML/jackson-databind/tree/3.x

Comment From: cowtowncoder

Second one (first is reference to a tag).