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

Support Type Id mappings where two ids map to same Class #312

Closed
cowtowncoder opened this issue Sep 18, 2013 · 10 comments
Closed

Support Type Id mappings where two ids map to same Class #312

cowtowncoder opened this issue Sep 18, 2013 · 10 comments
Milestone

Comments

@cowtowncoder
Copy link
Member

Currently default type id handlers do require mapping between ids and types (Classes) to be bijective; that is, neither side can have duplicates. This makes sense if both serialization and deserialization is required; if there are multiple choices, mapping would be ambiguous.

But for cases where Jackson is only used for deserializing, it may be useful to map more than one type id to a single class. It would be good if default type id serializer could support such usage; it is acceptable (and desirable) to throw an exception if such mapping was being used for serialization.

@umbreak
Copy link

umbreak commented Dec 11, 2013

The critical point in Polymorphism is the deserialization. When I have an JsonValue and I want to convert it to a class, is important that the object is an instance of the desired one.

This is a basic example. Only knowing the Type, provided by the enum should be enough to deserialize to the correct subclas:

enum Type{ PARROT,OWL, ZEBRA, SHEEP} 
class Animal{
    public Integer color;
    public Type animalType;
}
class Bird extends Animal{
    public Integer airSpeed;
    public Integer wingType;
}
class Mammal extends Animal{
    public Integer legs;
}

In the serialization process I don't see the problem:

Animal zebra=new Mammal();
zebra.animalType=ZEBRA;
zebra.legs=5;

Will this deserialization be ambiguous?

@cowtowncoder
Copy link
Member Author

I don't see ambituity in that example, as all ids for given base type are unique.

Critical point in round-trip handling may be serialization or deserialization, not just deserialization. Point being that if two types produce same id in serialization, deserialization will not be able to produce original types.

However: I am not saying that ambiguity is always problematic; because it is not. There are use cases where Jackson is only used for one direction; so -- for example -- deserializing multiple ids into one type is perfectly fine, and even desireable.
I only mentioned ambituity as one reason that supported original implementation, in which collection of ids happens in such a way that non-unique mappings are not preserved. It is a side effect and not explicitly added constraint.

All of which is to say: yes, I hope to relax these limitations, to allow use of non-bijective mappings.

@umbreak
Copy link

umbreak commented Dec 11, 2013

The ids are unique, but they're mapping the same classes. Following the example, how would it be possible to deserialized the polymorphisc objects using jackson with annotations? I would do it using @JsonTypeInfo like this

@JsonTypeInfo(  
    use = JsonTypeInfo.Id.NAME,  
    include = JsonTypeInfo.As.PROPERTY,  
    property = "animalType",
    visible = true)  
@JsonSubTypes({  
    @Type(value = Mammal.class, name = "ZEBRA"),  
    @Type(value = Mammal.class, name = "SHEEP"),  
    @Type(value = Bird.class, name = "PARROT"),
        @Type(value = Bird.class, name = "OWL")})
public class Animal{
//rest of the code from my previous post.

Something like that should work, in case several values could be asigned to the same class. However, it only works for ZEBRA and PARROT (the first values asigned to clases).

It should be possible to do it with those annotations. When is not, there is another solution (avoiding writting my own Serializator/Deserializator) ?

Thanks

@cowtowncoder
Copy link
Member Author

@umbreak Your example will not work currently; but if this RFE was implemented, it would, for deserialization.
That's the whole point. It would not work well if you started with an Animal and tried serialization -- serializer should probably throw an exception since there are multiple possibilities.

@umbreak
Copy link

umbreak commented Dec 12, 2013

For serialization animalType property should be checked in the class Animal. It contains the mapping information in any case. Only when you have an Animal class without any animalType there could be ambiguity.

//Serializer (approx. and without reflection and generics)
if (animal.animalType == Type.ZEBRA || animal.animalType == Type.SHEEP){
    Mammal mammal=(Mammal)animal;
    return mapper.writeValueAsString(mammal);
}else if (animal.animalType == Type.OWL || animal.animalType == Type.PARROT){
    Bird bird=(Bird)animal;
    return mapper.writeValueAsString(bird);
}

@cowtowncoder
Copy link
Member Author

@umbreak I don't think you are reading what I have written above. As I have repeatedly pointed out, mapping is not bijective which is WHY CURRENT IMPLEMENTATION WILL THROW AN EXCEPTION. And that further, with changes, IT WOULD START WORKING FOR DESERIALIZATION.

cowtowncoder added a commit that referenced this issue Feb 26, 2015
cowtowncoder added a commit that referenced this issue Feb 26, 2015
@cowtowncoder cowtowncoder added this to the 2.6.0 milestone Feb 26, 2015
@cowtowncoder
Copy link
Member Author

Implemented for 2.6.0.

@gimlet2
Copy link

gimlet2 commented Jul 19, 2018

It is still issue if you doing with public abstract void registerSubtypes(NamedType... types); method programmatically. It is backed with LinkedHashSet and NamedType is compared by Class only.

@cowtowncoder
Copy link
Member Author

@gimlet2 If there are follow up problems, could you please file a follow-up issue? It may reference this issue as background. I don't usually re-open old issues if fix in question has been published, as doing so complicates figuring out which version fix(es) go in.

@JoergHeinicke5005
Copy link

@gimlet2 Has this follow-up issue ever been created?

We are running exactly into the issue that registerSubtypes(..) doesn't work for use with mapping multiple types to the same class while it worked with annotating the super class. The latter we don't want to do anymore as it is a generic class not supposed to know about subtypes (also see #2104).

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

4 participants