使用改造将不一致的 JSON 解析为 POJO

Posted

技术标签:

【中文标题】使用改造将不一致的 JSON 解析为 POJO【英文标题】:Parse inconsistent JSON to POJO using retrofit 【发布时间】:2020-11-16 21:42:54 【问题描述】:

我有一个 JSON 响应,其中包含多个 JSON 对象。有时这些 JsonObject 包含数据,有时这些 JsonObject 包含一个空字符串。因此,当我使用改造 gson 转换器解析对 POJO 的 JSON 响应时,它会抛出“java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $”。我不确定如何处理这种动态响应。

我的 JSON


        "assetDetails": 
            "id": "0-0-175244",
            "rating": 5,
            "duration": 3538,
            "on_air": "true",
            "content_owner": "ghuiiio",
            "business_type": "premium_downloadable",
            "age_rating": "A",
            "title": "QWERTY",
            "actors": [
                "ABC",
                "PQR"
            ],
            "asset_type": 0,
            "original_title": "QWERTY",
            "directors": [
                "jgdhisl"
            ],
            "asset_subtype": "movie",
            "drm_key_id": "1cba26eb-9d76-4275-9a5c-c651640dc929",
            "subtitle_lang": [
                "en"
            ],
            "end_credits_start_s": "00:00:56",
            "orderid": 0,
            "extended": 
                "seo_title": "QWERTY",
                "broadcast_state": "",
                "music_directors": []
            ,
            "season_details": "",
            "description": "XYZ",
            "genres": [
                
                    "id": "Thriller",
                    "value": "Thriller"
                
            ],
            "release_date": "2020-06-27T00:00:00",
            "subtitle_languages": [
                "en"
            ],
            "languages": [
                "hi"
            ],
            "audio_languages": [
                "hi"
            ]
    

POJO

public class PlaybackDetails
    @SerializedName("assetDetails")
    private AssetDetails assetDetails;

    @SerializedName("watchHistoryDetails")
    private WatchHistoryDetails watchHistoryDetails;

    @SerializedName("trailerDetails")
    private Object trailerDetails;

    @SerializedName("keyOsDetails")
    private KeyOsDetails keyOsDetails;

    @SerializedName("entitlement")
    private Entitlement entitlement;

    @SerializedName("adDetails")
    private AdDetails adDetails;

    @SerializedName("showDetails")
    private ShowDetails showDetails;

    
    public void setAssetDetails(AssetDetails assetDetails)
        this.assetDetails = assetDetails;
    

    public AssetDetails getAssetDetails()
        return assetDetails;
    

    public void setWatchHistoryDetails(WatchHistoryDetails watchHistoryDetails)
        this.watchHistoryDetails = watchHistoryDetails;
    

    public WatchHistoryDetails getWatchHistoryDetails()
        return watchHistoryDetails;
    

    public void setTrailerDetails(Object trailerDetails)
        this.trailerDetails = trailerDetails;
    

    public Object getTrailerDetails()
        return trailerDetails;
    

    public void setKeyOsDetails(KeyOsDetails keyOsDetails)
        this.keyOsDetails = keyOsDetails;
    

    public KeyOsDetails getKeyOsDetails()
        return keyOsDetails;
    

    public void setEntitlement(Entitlement entitlement)
        this.entitlement = entitlement;
    

    public Entitlement getEntitlement()
        return entitlement;
    

    public void setAdDetails(AdDetails adDetails)
        this.adDetails = adDetails;
    

    public AdDetails getAdDetails()
        return adDetails;
    

    public void setShowDetails(ShowDetails showDetails)
        this.showDetails = showDetails;
    

    public ShowDetails getShowDetails()
        return showDetails;
    

    @Override
    public String toString()
        return 
            "PlaybackDetails" + 
            "convivaDetails = '" + convivaDetails + '\'' + 
            ",assetDetails = '" + assetDetails + '\'' + 
            ",watchHistoryDetails = '" + watchHistoryDetails + '\'' + 
            ",trailerDetails = '" + trailerDetails + '\'' + 
            ",keyOsDetails = '" + keyOsDetails + '\'' + 
            ",entitlement = '" + entitlement + '\'' + 
            ",adDetails = '" + adDetails + '\'' + 
            ",showDetails = '" + showDetails + '\'' + 
            "";
        


    public class AssetDetails
    
        @SerializedName("asset_subtype")
        private String assetSubtype;
    
        @SerializedName("audio_languages")
        private List<String> audioLanguages;
    
        @SerializedName("subtitle_languages")
        private List<String> subtitleLanguages;
    
        @SerializedName("rating")
        private int rating;
    
        @SerializedName("description")
        private String description;
    
        @SerializedName("title")
        private String title;
    
        @SerializedName("drm_key_id")
        private String drmKeyId;
    
        @SerializedName("extended")
        private Extended extended;
    
        @SerializedName("duration")
        private int duration;
    
        @SerializedName("episode_number")
        private int episodeNumber;
    
        @SerializedName("video_url")
        private VideoUrl videoUrl;
    
        @SerializedName("subtitle_lang")
        private List<String> subtitleLang;
    
        @SerializedName("genres")
        private List<GenresItem> genres;
    
        @SerializedName("business_type")
        private String businessType;
    
        @SerializedName("asset_type")
        private int assetType;
    
        @SerializedName("tvshow")
        private String tvshow;
    
        @SerializedName("season")
        private String season;
    
        @SerializedName("id")
        private String id;
    
        @SerializedName("skip_available")
        private SkipAvailable skipAvailable;
    
        @SerializedName("cover_image")
        private String coverImage;
    
        @SerializedName("slug")
        private String slug;
    
        @SerializedName("season_details")
        private SeasonDetails seasonDetails;
    
        @SerializedName("original_title")
        private String originalTitle;
    
        @SerializedName("is_drm")
        private int isDrm;
    
        @SerializedName("languages")
        private List<String> languages;
    
        @SerializedName("list_image")
        private String listImage;
    
        @SerializedName("age_rating")
        private String ageRating;
    
        @SerializedName("orderid")
        private int orderid;
    
        @SerializedName("image_url")
        private String imageUrl;
    
        @SerializedName("end_credits_start_s")
        private String endCreditsStartS;
    
        @SerializedName("content_owner")
        private String contentOwner;
    
        @SerializedName("tags")
        private List<String> tags;
    
        @SerializedName("channels")
        private List<ChannelsItem> channels;
    
        @SerializedName("web_url")
        private String webUrl;
    
        @SerializedName("release_date")
        private String releaseDate;
    
        public void setAssetSubtype(String assetSubtype)
            this.assetSubtype = assetSubtype;
        
    
        public String getAssetSubtype()
            return assetSubtype;
        
    
        public void setAudioLanguages(List<String> audioLanguages)
            this.audioLanguages = audioLanguages;
        
    
        public List<String> getAudioLanguages()
            return audioLanguages;
        
    
        public void setSubtitleLanguages(List<String> subtitleLanguages)
            this.subtitleLanguages = subtitleLanguages;
        
    
        public List<String> getSubtitleLanguages()
            return subtitleLanguages;
        
    
        public void setRating(int rating)
            this.rating = rating;
        
    
        public int getRating()
            return rating;
        
    
        public void setDescription(String description)
            this.description = description;
        
    
        public String getDescription()
            return description;
        
    
        public void setTitle(String title)
            this.title = title;
        
    
        public String getTitle()
            return title;
        
    
        public void setDrmKeyId(String drmKeyId)
            this.drmKeyId = drmKeyId;
        
    
        public String getDrmKeyId()
            return drmKeyId;
        
    
        public void setExtended(Extended extended)
            this.extended = extended;
        
    
        public Extended getExtended()
            return extended;
        
    
        public void setDuration(int duration)
            this.duration = duration;
        
    
        public int getDuration()
            return duration;
        
    
        public void setEpisodeNumber(int episodeNumber)
            this.episodeNumber = episodeNumber;
        
    
        public int getEpisodeNumber()
            return episodeNumber;
        
    
        public void setVideoUrl(VideoUrl videoUrl)
            this.videoUrl = videoUrl;
        
    
        public VideoUrl getVideoUrl()
            return videoUrl;
        
    
        public void setSubtitleLang(List<String> subtitleLang)
            this.subtitleLang = subtitleLang;
        
    
        public List<String> getSubtitleLang()
            return subtitleLang;
        
    
        public void setGenres(List<GenresItem> genres)
            this.genres = genres;
        
    
        public List<GenresItem> getGenres()
            return genres;
        
    
        public void setBusinessType(String businessType)
            this.businessType = businessType;
        
    
        public String getBusinessType()
            return businessType;
        
    
        public void setAssetType(int assetType)
            this.assetType = assetType;
        
    
        public int getAssetType()
            return assetType;
        
    
        public void setTvshow(String tvshow)
            this.tvshow = tvshow;
        
    
        public String getTvshow()
            return tvshow;
        
    
        public void setSeason(String season)
            this.season = season;
        
    
        public String getSeason()
            return season;
        
    
        public void setId(String id)
            this.id = id;
        
    
        public String getId()
            return id;
        
    
        public void setSkipAvailable(SkipAvailable skipAvailable)
            this.skipAvailable = skipAvailable;
        
    
        public SkipAvailable getSkipAvailable()
            return skipAvailable;
        
    
        public void setCoverImage(String coverImage)
            this.coverImage = coverImage;
        
    
        public String getCoverImage()
            return coverImage;
        
    
        public void setSlug(String slug)
            this.slug = slug;
        
    
        public String getSlug()
            return slug;
        
    
        public void setSeasonDetails(SeasonDetails seasonDetails)
            this.seasonDetails = seasonDetails;
        
    
        public SeasonDetails getSeasonDetails()
            return seasonDetails;
        
    
        public void setOriginalTitle(String originalTitle)
            this.originalTitle = originalTitle;
        
    
        public String getOriginalTitle()
            return originalTitle;
        
    
        public void setIsDrm(int isDrm)
            this.isDrm = isDrm;
        
    
        public int getIsDrm()
            return isDrm;
        
    
        public void setLanguages(List<String> languages)
            this.languages = languages;
        
    
        public List<String> getLanguages()
            return languages;
        
    
        public void setListImage(String listImage)
            this.listImage = listImage;
        
    
        public String getListImage()
            return listImage;
        
    
        public void setAgeRating(String ageRating)
            this.ageRating = ageRating;
        
    
        public String getAgeRating()
            return ageRating;
        
    
        public void setOrderid(int orderid)
            this.orderid = orderid;
        
    
        public int getOrderid()
            return orderid;
        
    
        public void setImageUrl(String imageUrl)
            this.imageUrl = imageUrl;
        
    
        public String getImageUrl()
            return imageUrl;
        
    
        public void setEndCreditsStartS(String endCreditsStartS)
            this.endCreditsStartS = endCreditsStartS;
        
    
        public String getEndCreditsStartS()
            return endCreditsStartS;
        
    
        public void setContentOwner(String contentOwner)
            this.contentOwner = contentOwner;
        
    
        public String getContentOwner()
            return contentOwner;
        
    
        public void setTags(List<String> tags)
            this.tags = tags;
        
    
        public List<String> getTags()
            return tags;
        
    
        public void setChannels(List<ChannelsItem> channels)
            this.channels = channels;
        
    
        public List<ChannelsItem> getChannels()
            return channels;
        
    
        public void setWebUrl(String webUrl)
            this.webUrl = webUrl;
        
    
        public String getWebUrl()
            return webUrl;
        
    
        public void setReleaseDate(String releaseDate)
            this.releaseDate = releaseDate;
        
    
        public String getReleaseDate()
            return releaseDate;
        
    
        @Override
        public String toString()
            return 
                "AssetDetails" + 
                "asset_subtype = '" + assetSubtype + '\'' + 
                ",audio_languages = '" + audioLanguages + '\'' + 
                ",subtitle_languages = '" + subtitleLanguages + '\'' + 
                ",rating = '" + rating + '\'' + 
                ",description = '" + description + '\'' + 
                ",title = '" + title + '\'' + 
                ",drm_key_id = '" + drmKeyId + '\'' + 
                ",extended = '" + extended + '\'' + 
                ",duration = '" + duration + '\'' + 
                ",episode_number = '" + episodeNumber + '\'' + 
                ",video_url = '" + videoUrl + '\'' + 
                ",subtitle_lang = '" + subtitleLang + '\'' + 
                ",genres = '" + genres + '\'' + 
                ",business_type = '" + businessType + '\'' + 
                ",asset_type = '" + assetType + '\'' + 
                ",tvshow = '" + tvshow + '\'' + 
                ",season = '" + season + '\'' + 
                ",id = '" + id + '\'' + 
                ",skip_available = '" + skipAvailable + '\'' + 
                ",cover_image = '" + coverImage + '\'' + 
                ",slug = '" + slug + '\'' + 
                ",season_details = '" + seasonDetails + '\'' + 
                ",original_title = '" + originalTitle + '\'' + 
                ",is_drm = '" + isDrm + '\'' + 
                ",languages = '" + languages + '\'' + 
                ",list_image = '" + listImage + '\'' + 
                ",age_rating = '" + ageRating + '\'' + 
                ",orderid = '" + orderid + '\'' + 
                ",image_url = '" + imageUrl + '\'' + 
                ",end_credits_start_s = '" + endCreditsStartS + '\'' + 
                ",content_owner = '" + contentOwner + '\'' + 
                ",tags = '" + tags + '\'' + 
                ",channels = '" + channels + '\'' + 
                ",web_url = '" + webUrl + '\'' + 
                ",release_date = '" + releaseDate + '\'' + 
                "";
            
    

在上面的 JSON 中,season_details 可以是 JSONObject,也可以是空的。

【问题讨论】:

你能发布你的 POJO 吗?您应该使用TypeAdapter (javadoc.io/doc/com.google.code.gson/gson/2.8.0/com/google/gson/…) 来解决给出错误的子对象的特定解析,但您需要知道如何处理“空字符串大小写”。 请粘贴各种json字符串。 【参考方案1】:

您可以使用自定义反序列化器来检查该值是否为真实对象,如果不是,则决定如何处理。

例如(用于任何类型):

public class StringOrObjectDeSerializer<T> implements JsonDeserializer<T> 
    // deserializer NOT registered with this Gson to prevent recursion!
    private final Gson innerGson = new Gson();

    @Override
    public T deserialize(JsonElement json, Type typeOfT, 
            JsonDeserializationContext context)
            throws JsonParseException 
        if (json.isJsonObject()) 
            return innerGson.fromJson(json, typeOfT);
        
        // null or some other default value for non-json-objects
        return null;
    

使用前注册即可,如:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(SeasonDetail.class, new StringOrObjectDeSerializer<>())
    .create();

如果您需要知道如何使用 Retrofit 注册它,请参阅this post

【讨论】:

以上是关于使用改造将不一致的 JSON 解析为 POJO的主要内容,如果未能解决你的问题,请参考以下文章

Retrofit2 - JSON 数组解析

为改造创建 pojo 类和回调

这是在没有 get/set-ters 的情况下改造 POJO 的正确方法吗?

改造 POJO 空

使用 gson 解析成 POJO 时,Json 总是返回 null

如何将查询的结果集转换为可以进一步解析以创建json的pojo类?