FasterXML / jackson-modules-java8

Set of support modules for Java 8 datatypes (Optionals, date/time) and features (parameter names)
Apache License 2.0
401 stars 117 forks source link

@JsonValue error #169

Closed yangle94 closed 4 years ago

yangle94 commented 4 years ago

https://github.com/yangle94/jsonValueError

please run main method in BookController.java。

@JsonValue on get method is success, but other fail.

cowtowncoder commented 4 years ago

First of all, thank you for reporting the problem.

Unfortunately I do not use tests that require use of external frameworks since there is a significant chance that the problem is within framework's integration with Jackson. Problem needs to be reproducible with just Jackson. Sometimes this means that issue should first be reported against framework project (like Spring Boot). If problem can be reproduced with just Jackson types, then a referenced sample project works well. But copy-pasting class(es) is ideal unless amount of code is large.

In addition, please include Jackson version, and a little bit about how failure occurs: is there an exception (if so, please include [part of] stack trace); does functionality do something other than what you expect. Code, even test code, is not necessarily enough to explain what you think is going wrong. This means that person looking at problem may misunderstand the issue.

Also: is there a reason to believe this is related to Java8 module? @JsonValue is handled by jackson-databind. I guess I can move the issue if I think it is databind problem.

kupci commented 4 years ago

@yangle94 The test would also need to be the post-processed class without the lombok annotations.

The only class in the test case related to the Java8 module is the reference to a parameter-names class, so likely a jackson-databind issue? Though that is the main difference in the test class. A stack trace would be helpful, to see where it is failing.

//success
ObjectMapper objectMapper2 = new ObjectMapper();
objectMapper2.readValue(json, BookPowerEntity2.class);

//fail
ObjectMapper objectMapper1 = new ObjectMapper();
objectMapper1.registerModule(new ParameterNamesModule());
        objectMapper1.readValue(json, BookPowerEntity.class);
yangle94 commented 4 years ago

I've reported springboot. link https://github.com/spring-projects/spring-boot/issues/20685

cowtowncoder commented 4 years ago

Looking at Enum serialization, I do not see anything wrong with @JsonValue, @JsonCreator usage with default settings of ObjectMapper, without parameter names module. Will see if module makes a difference.

cowtowncoder commented 4 years ago

Interesting. I can actually see following failure:

com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of `com.fasterxml.jackson.module.paramnames.EnumWithJsonValueTest$BookAggregateRootStatusEnum`, problem: argument type mismatch
 at [Source: (String)" 0"; line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.ValueInstantiationException.from(ValueInstantiationException.java:47)
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1742)
    at com.fasterxml.jackson.databind.DeserializationContext.handleInstantiationProblem(DeserializationContext.java:1116)
    at com.fasterxml.jackson.databind.deser.std.FactoryBasedEnumDeserializer.deserialize(FactoryBasedEnumDeserializer.java:146)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4434)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402)
    at com.fasterxml.jackson.module.paramnames.EnumWithJsonValueTest.testEnumWithValueOfCreator(EnumWithJsonValueTest.java:53)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.fasterxml.jackson.databind.introspect.AnnotatedMethod.callOnWith(AnnotatedMethod.java:116)
    at com.fasterxml.jackson.databind.deser.std.FactoryBasedEnumDeserializer.deserialize(FactoryBasedEnumDeserializer.java:138)
    ... 27 more
cowtowncoder commented 4 years ago

@yangle94 This is actually due to ambiguity wrt single-argument Creator methods, common with POJOs, Java 8 module. To fix it, add mode to JsonCreator like so:

@JsonCreator(mode = JsonCreator.Mode.DELEGATING)

which will make sure Jackson does not try to use "properties" style accidentally (in this case it notices there is code logical property and incorrectly guesses you want that style. I think I may want to add an extra check in logic to change handling for Enums but it is probably best to just have that mode in there regardless of heuristics work.

cowtowncoder commented 4 years ago

Ok: I did improve error handling so that 2.11.0 should give more meaningful error message; something that should point to right direction. But after thinking it through, I don't think I should try to change the logic since this particular case is no more likely to be clear-cut for Enums than POJOs -- there is still potential confusion on delegate-or-single-property, something that should be handled for all types. Changing it just for Enums is likely to just lead to further confusion.