How to identify the missing type id in Jackson error?

20,354

UPDATE:

BusinessContact class should be annotated with @JsonTypeName("business") and PersonContact class with @JsonTypeName("personal") instead of @JsonTypeName("type") because you shoud define specific type in inheritors.

@JsonTypeInfo annotation can be removed from subclasses at all.

UPDATE 2:

Additionaly PersonContact class should have default constructor:

public PersonContact(){}

An input JSON file is not a list it is an entity with two attributes allContacts and size. Thus it can't be mapped to ArrayList<BaseContact>. So a new entity with these two attributes should be created:

public class ContactsWrapper
{
   private List<BaseContact> allContacts;
   private int size;

   public List<BaseContact> getAllContacts()
   {
      return allContacts;
   }

   public void setAllContacts(List<BaseContact> allContacts)
   {
      this.allContacts = allContacts;
   }

   public int getSize()
   {
      return size;
   }

   public void setSize(int size)
   {
      this.size = size;
   }
}

Code that reads JSON should be changed:

ContactsWrapper contactsWrapper = new ObjectMapper().readerFor(ContactsWrapper.class).readValue(new File(fn));
abl = contactsWrapper.getAllContacts();

Now JSON is mapped to ContactsWrapper and list of contacts is assigned to abl variable using getter.

Share:
20,354
james
Author by

james

Updated on July 13, 2022

Comments

  • james
    james almost 2 years

    I am using Jackson to write JSON to a text file, the JSON represents 2 classes inherited from an abstract class but the error also occurs irrespective of whether both or either/or classes are used. The JSON appears to be written correctly but on reading, I get the following error:

    Missing type id when trying to resolve subtype of [simple type, class model.BaseContact]: missing type id property 'type'
         at [Source: (File); line: 52, column: 1]
    json as follows:
        {
       "allContacts" : [ {
         "type" : "personal",
        "addressCity" : "Hamilton",
        "addressNum" : "199",
       "addressPOBox" : null,
        "addressPostCode" : null,
        "addressStreet" : "River Rd",
        "addressSuburb" : null,
        "email" : null,
        "latitude" : null,
        "longitude" : null,
        "name" : "silly simon",
        "notes" : null,
        "phoneNumber" : "09754321",
        "photoBytes" : null,
        "photoURL" : null
      }, {
        "type" : "personal",
        "addressCity" : "Auckland",
        "addressNum" : "482",
        "addressPOBox" : null,
        "addressPostCode" : null,
        "addressStreet" : "Smith Rd",
        "addressSuburb" : null,
        "email" : null,
        "latitude" : null,
        "longitude" : null,
        "name" : "paul smith",
        "notes" : null,
        "phoneNumber" : "0544555",
        "photoBytes" : null,
        "photoURL" : null
      }, {
        "type" : "personal",
        "addressCity" : "Appleby",
        "addressNum" : "123",
        "addressPOBox" : null,
        "addressPostCode" : null,
        "addressStreet" : "Apple rd",
        "addressSuburb" : null,
        "email" : null,
        "latitude" : null,
        "name" : "Steve Jobbs",
        "notes" : null,
        "phoneNumber" : "08004343",
        "photoBytes" : null,
        "photoURL" : null
      } ],
      "size" : 3
    }
    

    The error message refers to line 52 column 1, assuming the debugger starts at line 1 that would be the line after the final curly brace.

    The BaseContact class header is as follows:

    import com.fasterxml.jackson.annotation.JsonSubTypes;
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    
    @JsonTypeInfo(
            use=JsonTypeInfo.Id.NAME,
            include=JsonTypeInfo.As.PROPERTY,
            property="type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value=PersonContact.class, name= "personal"),
            @JsonSubTypes.Type(value= BusinessContact.class, name="business")
    })
    
    public  abstract class BaseContact {
    
    public String name;
    public String addressNum;
    public String addressStreet;
    public String addressSuburb;
    public String addressCity;
    public String addressPOBox;
    public String addressPostCode;
    public Double latitude;
    public Double longitude;
    
    public String photoURL;
    public String photoBytes;
    public String phoneNumber;
    public String email;
    
    public String notes;
    
    public BaseContact() {
        //DEFAULT CONSTRUCTOR
    
    }
    
    
        public BaseContact( String name, String addressNum, String addressStreet, 
        String addressCity, String phoneNumber) {
    
        this.name = name;
        this.addressNum = addressNum;
        this.addressStreet = addressStreet;
        this.addressCity = addressCity;
        this.phoneNumber = phoneNumber;
    }
    

    The calling function is as follows:

     public BusinessService readAllData(String fn) {
      ArrayList<BaseContact> abl = new ArrayList<BaseContact>();
                try {
                    abl = new ObjectMapper().readerFor(BaseContact.class).readValue(new File(fn));
                    Log.d("qq","abl"+ abl);
                } catch (IOException e) {
                    Log.d("qq", "failed reading " + e.getMessage().toString());
                    e.printStackTrace();
                }
    
    
                 BusinessService b = new BusinessService();
                return b;
        }
    

    The BusinessContact class ( inherits from abstract BaseContact) is as follows:

    package model;
    
    import com.fasterxml.jackson.annotation.JsonTypeName;
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    @JsonTypeInfo(
        use=JsonTypeInfo.Id.NAME,
        include=JsonTypeInfo.As.PROPERTY,
        property="type")
    @JsonTypeName("type")
    public class BusinessContact extends BaseContact {
    public String companyName;
    public String websiteURL;
    public String businessHours;
    //def constructor
    public BusinessContact(){
    };
    public BusinessContact(String name,  String addressNum, String addressStreet, 
    String addressCity, String phoneNumber, String companyName, String websiteURL, String businessHours) {
        super(name, addressNum, addressStreet, addressCity, phoneNumber);
        this.companyName = companyName;
        this.websiteURL = websiteURL;
        this.businessHours = businessHours;
    }
    
    //Getters and setters
    public String getCompanyName() {
        return companyName;
    }
    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
    public String getWebsiteURL() {
        return websiteURL;
    }
    public void setWebsiteURL(String websiteURL) {
        this.websiteURL = websiteURL;
    }
    public String getBusinessHours() {
        return businessHours;
    }
    public void setBusinessHours(String businessHours) {
        this.businessHours = businessHours;
    }
    public String visitWebsite(int i ){
        //get website, construct intent
        return"url intent";
    }
    public Boolean isOpen(int i ){
        //do math for day and time and return true if open
        return true;
    }
    @Override
    public String toString() {
        String output= this.getClass() + "name: "+ this.name + " " + "company"+ this.companyName + "Hours "+ this.businessHours + "Website "+ this.websiteURL+ " address: " + this.addressNum+ " , " + this.addressStreet + " , " + this.addressSuburb+ "," +
                this.addressCity +" , CODE " + this.addressPostCode + " PO BOX " + this.addressPOBox + "PH: " +  this.phoneNumber + "email: " + this.email + "notes: "+ this.notes ;
        return output ;
    }
    

    }

    The PersonContact class ( inherits from abstract BaseContact):

    package model;
    import com.fasterxml.jackson.annotation.JsonSubTypes;
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    import com.fasterxml.jackson.annotation.JsonTypeName;
    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.PROPERTY,
            property = "type")
    @JsonTypeName("type")
    public class PersonContact extends BaseContact {
       //constructor
        public PersonContact(String name, String addressNum, String addressStreet, String addressCity, String phoneNumber) {
            super(name, addressNum, addressStreet, addressCity, phoneNumber);
        }
        @Override
        public String toString() {
            String output = this.getClass() + "name: " + this.name + " " + " address: " + this.addressNum + " , " + this.addressStreet + " , " + this.addressSuburb + "," +
                    this.addressCity + " , CODE /n " + this.addressPostCode + " PO BOX " + this.addressPOBox + "PH: " + this.phoneNumber + "email: " + this.email + "notes: " + this.notes;
            return output;
        }
    }
    
  • james
    james over 4 years
    Thanks , I have made those changes yet I still get "failed reading Missing type id when trying to resolve subtype of [simple type, class model.BaseContact]: missing type id property 'type' "
  • Ihor Patsian
    Ihor Patsian over 4 years
    I've updated the answer with additional steps that fix your problem. Please see UPDATE 2 section.
  • james
    james over 4 years
    I cant upvote your answer but UPDATE2 is effective, many thanks Igor
  • vphilipnyc
    vphilipnyc over 3 years
    The NoArg constructor part was helpful here