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
JsonTypeInfo is ignored when serializing a list of annotated object #336
Comments
Yes and no: this is due Java Type Erasure. It is missing because element type information is not available to Jackson; all it sees is So question then is how to pass the extra information needed to detect the type.
Note that type erasure is only problematic for root values (value directly passed to |
Thanks a lot. I think I made a mistake adding an issue for it. Sorry.
objectMapper.writeValueAsStringWithJsonTypeInfoConsideration(o, 2013/10/28 Tatu Saloranta notifications@github.com
|
Np, it is a common problem unfortunately -- and it's not obvious from outset whose fault it is. The reason is that when deserializing you will not know "real type" -- this is what |
I just dug this up and accepted the answers (sort of): When adding enableDefaultTyping to the mapper, it suddenly adds type infos to the serialized stream, so why can't it use the same mechanism it uses to detect the base type in that case? I mean not just adding the detected baseType but use that type to then search for the annotation on this type. |
There are two problems: correctness for deserialization, and performance. Or perhaps just one, that of performance for both sides. Additional per-element lookups are significant overhead, and would take more time than actual reading, writing and data-binding of data. So at least by default this does not seem compelling. I am also not confident that changing behavior to allow potentially differing type information on serialization (possibly rare case, but I have noticed users using different But all in all, I think I will add a note somewhere that says that Jackson recommends that users DO NOT try directly serializing any |
Performance and Deserialization is not really important for my use case: Javascipt frameworks like Angular or ExtJS which have some nice features where you may directly pipe stuff into sorted, filtered lists and little goblins do all the work for you. But this is working a lot better out of the box if the root node is an array. If not, you have to manually unwrap it yourself. The guys designing those stuff of course don't think about Java limitations. Manually unwrapping is of course not a big problem, but still a bit annoying if you have to do it over and over again. I can't use any of the available enableDefaultTyping options because then sublists get wrapped in an array which then breaks things at other places. Couldn't the default behavior used when enableDefaultTyping is activated be enabled via an additional mapper option enableJsonTypeInfoProcessingOnRootContainers you explicitly have to enable? Then it wouldn't break anything. If this is a feature that could be implemented by changing a few lines of code, I would really like to have it. If not I keep wrapping stuff :) |
Or what also would help - at least for my use cases - enableNonRecursiveDefaultTyping |
I guess I am not 100% sure what exactly is the problem in your case -- due to long history here, I may be assuming things. But one thing about default typing is that determination of what kind of values should use type id is fully configurable. So it may be possible that you either need to use different standard criteria (one of pre-defined ones), or implement your own rule. Determination is never done on basis of hierarchy (there isn't enough information available to do that), but purely based on class in question. It might make sense to just file a new issue, and explain the problem with simple example; I realize that it is related to problem reported here, but it sounds like you have some additional structural differences. |
Maybe I'm missing something, if I use DefaultTyping.JAVA_LANG_OBJECT which I understand shouldn't do anything to lists, I get this: [ { The root list is as I need it, but the someArray sublist inside the map gets wrapped. I don't want that and also don't understand why it is happening. Is there an example how to "implement my own rule" that I may then use? |
It does not do anything to the So, for example, POJO like: class POJO {
public List<String> values;
} would not get any type info. But if you are passing root-level List, then it is typically only known as You can explicitly pass in type to consider for value, something like: mapper.writerWithType(new TypeReference<List<String>>() {} ).writeValueAsString(list); and then type is recognized as I guess your example goes bit deeper, but the same principle applies: declared type must be enough to determine base type, used for determining whether polymorphic handling applies (and if so, with what configuration). One further caveat is with generic types. Jackson can handle type parameter resolution when there is enough information in most cases, but Java type erasure means that type is not always available when you think it is. Specifically, having parametric type like: class Wrapper<T> {
public List<T> values;
} will NOT have any runtime type parameters, if instantiated with: Wrapper<POJO> wrapper = new Wrapper<POJO>(); However, a subtype like: class POJOWrapper extends Wrapper<POJO> { } DOES have parameterization available. So only in latter case would If you can share specific class declaration(s) involved, I may be able to help add type information (either via |
Thanks, I understand what you are telling, but I don't understand how that applies to my example: [/_this is in Java defined as List (not ArrayList) it is not wrapped as [ "java.util.ArrayList", actualList] */ What I need is type annotations where possible without messing around with the datastructure. |
I can only help if you provide the class description, and piece of code you are using. |
What I serialize is defined like this: Then I create an ObjectMapper and call mapper.enableDefaultTyping(DefaultTyping.JAVA_LANG_OBJECT); The output is the one above. I can't easily change any of the rootLists and subLists type definitions, So I would like to come up with a solution where the Mapper creates "Type ids" only as properties but doesn't change the lists ([ "java.util.ArrayList", actualList]). BTW: Thanks for your help |
Ok. So, the root value you give will be consider to have type If you defined, say, root type like so: mapper.writerForType(new TypeReference<List<Map<String,List<?>>>() { })
.writeValueAsString(); type information would NOT be included for But if you can not specify more specific typing, Jackson type id handling just might not work in your case, and you would possibly need to implement custom serializer, deserializer. |
I guess I'll have to do that as maps/lists/simple values occur mixed in maps/lists. Where is the wrapping actually done? I looked at the code of CollectionSerializer which calls JsonGenerator for start and end tags, but I couldn't find anything about that in JsonGeneratorImpl |
Registration varies a bit; for serialization, look up will be using actual runtime type (unless configured explicitly to use declared static type). For deserialization declared type is needed; and you will have same dualism so that you will actually need to register deserializer for Another possibility, which might end up being less work would be to do 2-phase processing: first read as Actually you can also combine approaches; deserializer can call |
Thanks again :) I never need to deserialize anything, I would like to create a new module with a modified CollectionSerializer stolen from jackson-databind. I just didn't find the place where the wrapping is currently done: I guess it is done somewere in JsonGenerator? Serialization is based on runtime type. I understand :) But my question was will module.addSerializer(Collection.class, new StolenCollectionSerializer()) override all the default serializers for all subtypes of Collection? Or an example: module.addSerializer(Collection.class, new MyCollectionSerializer()) Which one will be elected for lets say runtime type ArrayList? |
No, JsonGenerator does not get involved with data-binding in any way, it is strictly streaming-only. As So in your case you will need to implement At this point let's switch over to Jackson dev list -- github issues are fine for bug reports etc, but in this case this is kind of documentation that others may find useful and be able to able with. |
Don't you think this will work ?
This will force the even with generics you will always have |
@goldenrat That will simply add type-erased |
I think I'm having the same problem, but how to solve it ? |
@jgribonvald Please either discuss this on user mailing list, or create a new issue (if it's for XML, for Thanks! |
It seems that JsonTypeInfo is somehow ignored when serializing a list of annotated object. The following is some piece of code describing the situation.
The following two pieces of code produce the results shown:
Outputs: {"id":10, "clazz":"Task"}
Outputs: [{"id":10}]
"clazz" is not produced in the second code. why?
The text was updated successfully, but these errors were encountered: