-
-
Notifications
You must be signed in to change notification settings - Fork 143
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
@JsonProperty is ignored, sometimes #197
Comments
I am using version 2.4.4 |
|
While it is not guaranteed to change things, I would suggest latest patch release, 2.4.5, since |
I've tried version 2.4.5 to no avail. I will have to remove these annotations in order to avoid this issue. |
Thanks for reporting this. I know it's terribly inconvenient. This might be a lot to ask, but are you able to reproduce this problem with an Oracle JDK? We've had other reports (#189) of issues when using OpenJDK, and I suspect this may be related. |
@christophercurrie This is occurring on Oracle Hotspot JDK as well. |
Cool, thanks for checking. I'll see if I can reproduce this. You might also try Jackson 2.5.2, for which the Scala module has improved certain aspects of property detection. |
Upon upgrading to Jackson 2.5.2 I find compilation errors that seem to require properties to be unwrapped require the @JsonProperty annotation as well. In referencing my example above. Is this expected? Even though there will never be a JSON field named "myClass". |
Not expected, and I especially wouldn't expect compilation errors. What errors is the compiler giving you? |
@christophercurrie Sorry not a compilation error, but a runtime exception |
Upgrading to Jackson 2.5.2 has exacerbated the problem. Even more instances of ignored @JsonProperty annotations. |
The description here is only one of the manifestations of the problem. The exact class hierarchy and their fields do not matter. We see it happening randomly on any class in our class hierarchy. It is happening during startup - first request and stays for the process lifetime. Jackson properly walk the class and find all the fields. However it sometimes does not process @JsonProperty annotations. Are those two separate steps? Can there be a race condition between them? Or can multiple ObjectMappers hurt? @christophercurrie would you have any tip where to look? It looks like some race condition. |
I suppose a race condition is possible, but I am more likely to suspect the fact that Java reflection, upon which Jackson is based, stopped providing consistent ordering of methods, fields, and annotations, as of Java 7. A good test of this theory would be to run the relevant code under a Java 6 JVM which, despite Oracle's discontinuation of support, is still the only JVM version upon which any guarantees are made for Scala (and which the library must still support). Which is not to say that this issue shouldn't be fixed, just that it is both hard to reproduce and diagnose. If the issue appears in Java 6, then it's not due to reflection ordering, and will be relatively simple to locate and fix. If not, then it's almost certainly an ordering issue, and diagnosing it will likely require repeated traces with a debugger. This issue is definitely on my list to address, but I have not had the time to investigate. |
@jendap Multiple |
I will find it. It is top priority for us. We are loosing money on it. Unfortunately I can't even after two days replicate it locally. (which is also why I suspect race condition). But we have a production heap dump. We can see anything including the data from java reflection. Comparing the BeanSerializer... Do you think adding the JsonProperty annotation on methods as well as on fields can make difference? We can try java6 on a few nodes. The problem is that we need G1 garbage collector to keep our SLA. And if we put it on a few nodes and restart a couple of times it is hard to say if it is not happening for sure. Currently it is probably something like 1 in 20 restarts. |
Re annotation location: without looking at your specific code is is hard to say, but maybe. If you're using case classes, and the annotations are on the constructor parameters, it might be useful to try change |
Yes, that case class with annotated fields is exactly what we use and I'm going to change it to what you have described. We will see next week after a couple of deployments if it will work. Thanks! |
Ok, forcing the annotation to all the places - param, field, getter - works well. But it is rather ugly hack and even worse it will bite a lot more people in very bad way. We have lost a lot of money on this. Can you tell point me to where this listing is happening for scala case class? I would like to look at it how to fix it (and replicate). Thanks! BTW: This is what we use now. We import from our.package.JacksonAnnotations._ instead of com.faster.xml.jackson.annotations._. And our JacksonAnnotations is this: import scala.annotation.meta.field
import scala.annotation.meta.getter
import scala.annotation.meta.param
object JacksonAnnotations {
type JsonSerialize = com.fasterxml.jackson.databind.annotation.JsonSerialize @param @field @getter
type JsonDeserialize = com.fasterxml.jackson.databind.annotation.JsonDeserialize @param @field @getter
type JsonIgnore = com.fasterxml.jackson.annotation.JsonIgnore @param @field @getter
type JsonIgnoreProperties = com.fasterxml.jackson.annotation.JsonIgnoreProperties @param @field @getter
type JsonInclude = com.fasterxml.jackson.annotation.JsonInclude @param @field @getter
type JsonProperty = com.fasterxml.jackson.annotation.JsonProperty @param @field @getter
type JsonTypeInfo = com.fasterxml.jackson.annotation.JsonTypeInfo @param @field @getter
type JsonUnwrapped = com.fasterxml.jackson.annotation.JsonUnwrapped @param @field @getter
} |
The relevant class is As far as I can tell, the triggering issue is that Java 7+ reflection will provide the methods and classes to Jackson in different orders each time the JVM is created (though it's likely that the order is stable during a particular JVM run). Simulating this failure would involve asking Jackson to generate the // NB: off the cuff, might not compile
val appType = mapper.constructType(classOf[App])
val serialzationConfig = mapper.getSerializationConfig()
val ai = serializationConfig.getAnnotationIntrospector()
val beanDesc = serializationConfig.introspectDirectClassAnnotations(appType)
val annotatedClass = beanDesc.getClassInfo()
// play around with annotatedClass.fields() and annotatedClass.memberMethods()
// to find the broken order, e.g.:
for (method <- annotatedClass.memberMethods().asScala) {
val name = ai.findNameForSerialization(method);
} I don't really know what you might find though; I would not expect this ordering to matter, but it is the only common thread between bug reports of this nature, that they are using Java 7 or 8. That said, looking at
I don't really know how the deficiencies above would actually result in failures, largely because looking at the constructor parameter is generally the right thing to do. It's possible that there are circumstances where the property detection logic can't find the constructor parameter when it should. The change above might be something to try if you're able to reproduce the problem. If I have time, I will also take another look at this issue. |
For what it is worth, I am also puzzled by the problem, since ordering of methods, constructors should not any significance. But it sounds like it may well be the thing that triggers whatever the actual problem is. |
@cowtowncoder, the difficulty with what This falls down in Scala because a single entry in the code generates many different JVM artifacts. class Foo(@JsonProperty("bar") var foo: String) This definition creates four different JVM artifacts: the constructor parameter, the field, the getter, and the setter. However, by default, the annotation appears only on the constructor parameter, resulting in incorrect serialization. Similar behavior happens for fields. The |
@christophercurrie Actually constructor parameter should by now be visible to serialization purposes as well; 1.9 was the version that unified handling of annotations. Before 1.9 this was not the case. There being a bug is not completely out of the question, partly because detection and use of creator parameters is much more complicated than that of simple fields or setters/getters. But the mechanism should combine annotations from different "accessors" (term used to denote members like fields, getters and setters, and creator parameters that act as virtual setters). Another module that formerly did its own unification is JAXB annotations module. It may still try some of that (to try to support JAXB package level annotations), but for the most part has been simplified to do less work. |
I'll be ecstatic if that's the case, but I'm not quite sure how property naming via constructor parameter annotation could have been supported prior to Java 8 parameter name detection. A Java-based example: class Foo {
private String foo;
private Foo(@JsonProperty("bar") String foo) { this.foo = foo; }
private String getFoo() { return foo; };
private void setFoo(String foo) { this.foo = foo; }
} This is the Java equivalent of what the Scala code would produce. Without implicit parameter names, I would expect this produce |
Correct, this would not have worked without implicit names. Whether it works with implicit names is an interesting question, but I think it should, considering that similar approach with other accessors would work. In above case, making things click would have required one additional annotation on either field, setter or getter, to declare renaming as "bar". If so, all the other annotations would have been unified. |
I'm beginning to believe that I may be on the wrong track; the reason is that this problem exists in 2.4.4, and the ScalaAnnotationIntrospector is 2.5+ code only. I have another theory, but I need to confirm a couple of things first. I'll get back to you asap. |
Thank you for working on this guys! The thing I still don't understand is that it is random with every restart. Same machine, same jvm, exactly the same jar file and classpath gives random outcome. The patch does not fix anything like that. Could it be some sort of race condition? Java 7/8 have multi-threaded class loading enabled by default. But I can't see it. Anyway, if jackson double check the annotations on constructor parameters every time it should do the trick. Is it just that tiny commit in jackson-databind? Or do you think more is needed? I can test it in our production. |
I'm fairly confident there is more to do, but I haven't yet found the root cause. The patch addresses separate issues that will improve annotation handling for 2.6, but I don't think that's what's at work here. I'm starting to suspect something in the caching that happens internally to either the Scala module or core jackson. The trouble is, despite lots of examples, I have yet to observe the issue locally. It seems there might be some other environment factors influencing the behavior. |
Not sure this is super helpful, but I'm having the same problem and thought I'd chime in. Our auto integration tests fail intermittently when a @JsonProperty is ignored. We're using: -version 2.5.2 The workaround proposed by @jendap above is doing the job for us, thanks for that! Still, I obviously look forward to removing the hack when this is resolved. |
Another note that may or may not help, but version 2.5.3 of Scala module is now available as well. |
That said, I don't know of any changes in 2.5.3 that will solve the root cause. I apologize that this continues to be an issue. |
No apology needed, obviously this is a hairy one or it would be fixed. Thanks :) No luck with 2.5.3, I still need the @jendap workaround. |
So actually 2.5.3 seems to introduce a different issue, also intermittent, but not resolved by the workaround:
Reverted to 2.5.2 and all is good again, using the workaround. |
The issue with Creator in 2.5.3 is likely something else. @jnadler are you able to reproduce it on a small codebase you could share? I have spend a day or more of work trying to replicate it outside of our full production system but unsuccessfully. It should not be that hard to fix it once we can replicate it. |
Reproduce which? The original 2.5.2 problem or the 2.5.3 Creator issue? I can try to boil it down to a simple project. |
Ideally both of them! :-) |
Sorry for the very late follow up. I have reason to believe that the original issue here is resolved by FasterXML/jackson-databind#868, which is fixed in Jackson 2.6.0 and later. The Scala module is currently behind in the release cycle, having only a 2.6.1 release, while core Jackson is at 2.6.3. Please let me know if upgrading to 2.6.1 or later resolves this issue for you. |
do we have any update on this, we are using 2.6.2 version and getting this issue. |
This has been resolved for me when upgrading to 2.7.4. |
Neither me nor @brefsdal work in the environment where we could replicate it. So we can't confirm for sure.... But it looks like it was fixed in 2.6.1. I think we can close this. Thank you @christophercurrie! |
Assuming this is fixed: if not, would make sense to re-file, I think, with reproduction, info on version failing. |
I've found a case where the JsonProperty annotation is ignored by the serializer. Sometimes. Unfortunately, I haven't found out why this occurs, seemly at random. Here is a example schema
Most of the time I'll see 'my_name' in the output JSON string. Sometimes a machine will output
myName
. Once the machine starts outputting camelcase like this, it continues to do so until I restart the JVM. Here is the configuration of the ObjectMapper belowThe text was updated successfully, but these errors were encountered: