解析不一致的JSON为POJO,使用Retrofit。

huangapple 未分类评论63阅读模式
英文:

Parse inconsistent JSON to POJO using retrofit

问题

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; // This can be JSONObject or empty

    @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;
    }

    // ... (getters and setters for other fields)

    public void setSeasonDetails(SeasonDetails seasonDetails) {
        this.seasonDetails = seasonDetails;
    }

    public SeasonDetails getSeasonDetails() {
        return seasonDetails;
    }

    // ... (toString method and other methods)
}
public class SeasonDetails {
    // Define fields for SeasonDetails
    // This class can represent the structure of the JSONObject within "season_details"
}

In the AssetDetails class, the seasonDetails field is defined to be of type SeasonDetails. This allows it to represent the nested JSON object within the "season_details" field of the JSON response. Since you mentioned that "season_details" can be either a JSONObject or empty, this structure should accommodate both cases.

英文:

I have a JSON response which contains multiple JSON object in it. Sometimes these JsonObject contains data and sometimes these JsonObject contain an empty string. So when I am parsing this JSON response to POJO using retrofit gson converter, it's throwing "java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $". I am not sure how to handle such dynamic response.

My JSON:

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

POJO:

public class PlaybackDetails{
	@SerializedName(&quot;assetDetails&quot;)
	private AssetDetails assetDetails;

	@SerializedName(&quot;watchHistoryDetails&quot;)
	private WatchHistoryDetails watchHistoryDetails;

	@SerializedName(&quot;trailerDetails&quot;)
	private Object trailerDetails;

	@SerializedName(&quot;keyOsDetails&quot;)
	private KeyOsDetails keyOsDetails;

	@SerializedName(&quot;entitlement&quot;)
	private Entitlement entitlement;

	@SerializedName(&quot;adDetails&quot;)
	private AdDetails adDetails;

	@SerializedName(&quot;showDetails&quot;)
	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 
			&quot;PlaybackDetails{&quot; + 
			&quot;convivaDetails = &#39;&quot; + convivaDetails + &#39;\&#39;&#39; + 
			&quot;,assetDetails = &#39;&quot; + assetDetails + &#39;\&#39;&#39; + 
			&quot;,watchHistoryDetails = &#39;&quot; + watchHistoryDetails + &#39;\&#39;&#39; + 
			&quot;,trailerDetails = &#39;&quot; + trailerDetails + &#39;\&#39;&#39; + 
			&quot;,keyOsDetails = &#39;&quot; + keyOsDetails + &#39;\&#39;&#39; + 
			&quot;,entitlement = &#39;&quot; + entitlement + &#39;\&#39;&#39; + 
			&quot;,adDetails = &#39;&quot; + adDetails + &#39;\&#39;&#39; + 
			&quot;,showDetails = &#39;&quot; + showDetails + &#39;\&#39;&#39; + 
			&quot;}&quot;;
		}
}

    public class AssetDetails{
    
    	@SerializedName(&quot;asset_subtype&quot;)
    	private String assetSubtype;
    
    	@SerializedName(&quot;audio_languages&quot;)
    	private List&lt;String&gt; audioLanguages;
    
    	@SerializedName(&quot;subtitle_languages&quot;)
    	private List&lt;String&gt; subtitleLanguages;
    
    	@SerializedName(&quot;rating&quot;)
    	private int rating;
    
    	@SerializedName(&quot;description&quot;)
    	private String description;
    
    	@SerializedName(&quot;title&quot;)
    	private String title;
    
    	@SerializedName(&quot;drm_key_id&quot;)
    	private String drmKeyId;
    
    	@SerializedName(&quot;extended&quot;)
    	private Extended extended;
    
    	@SerializedName(&quot;duration&quot;)
    	private int duration;
    
    	@SerializedName(&quot;episode_number&quot;)
    	private int episodeNumber;
    
    	@SerializedName(&quot;video_url&quot;)
    	private VideoUrl videoUrl;
    
    	@SerializedName(&quot;subtitle_lang&quot;)
    	private List&lt;String&gt; subtitleLang;
    
    	@SerializedName(&quot;genres&quot;)
    	private List&lt;GenresItem&gt; genres;
    
    	@SerializedName(&quot;business_type&quot;)
    	private String businessType;
    
    	@SerializedName(&quot;asset_type&quot;)
    	private int assetType;
    
    	@SerializedName(&quot;tvshow&quot;)
    	private String tvshow;
    
    	@SerializedName(&quot;season&quot;)
    	private String season;
    
    	@SerializedName(&quot;id&quot;)
    	private String id;
    
    	@SerializedName(&quot;skip_available&quot;)
    	private SkipAvailable skipAvailable;
    
    	@SerializedName(&quot;cover_image&quot;)
    	private String coverImage;
    
    	@SerializedName(&quot;slug&quot;)
    	private String slug;
    
    	@SerializedName(&quot;season_details&quot;)
    	private SeasonDetails seasonDetails;
    
    	@SerializedName(&quot;original_title&quot;)
    	private String originalTitle;
    
    	@SerializedName(&quot;is_drm&quot;)
    	private int isDrm;
    
    	@SerializedName(&quot;languages&quot;)
    	private List&lt;String&gt; languages;
    
    	@SerializedName(&quot;list_image&quot;)
    	private String listImage;
    
    	@SerializedName(&quot;age_rating&quot;)
    	private String ageRating;
    
    	@SerializedName(&quot;orderid&quot;)
    	private int orderid;
    
    	@SerializedName(&quot;image_url&quot;)
    	private String imageUrl;
    
    	@SerializedName(&quot;end_credits_start_s&quot;)
    	private String endCreditsStartS;
    
    	@SerializedName(&quot;content_owner&quot;)
    	private String contentOwner;
    
    	@SerializedName(&quot;tags&quot;)
    	private List&lt;String&gt; tags;
    
    	@SerializedName(&quot;channels&quot;)
    	private List&lt;ChannelsItem&gt; channels;
    
    	@SerializedName(&quot;web_url&quot;)
    	private String webUrl;
    
    	@SerializedName(&quot;release_date&quot;)
    	private String releaseDate;
    
    	public void setAssetSubtype(String assetSubtype){
    		this.assetSubtype = assetSubtype;
    	}
    
    	public String getAssetSubtype(){
    		return assetSubtype;
    	}
    
    	public void setAudioLanguages(List&lt;String&gt; audioLanguages){
    		this.audioLanguages = audioLanguages;
    	}
    
    	public List&lt;String&gt; getAudioLanguages(){
    		return audioLanguages;
    	}
    
    	public void setSubtitleLanguages(List&lt;String&gt; subtitleLanguages){
    		this.subtitleLanguages = subtitleLanguages;
    	}
    
    	public List&lt;String&gt; 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&lt;String&gt; subtitleLang){
    		this.subtitleLang = subtitleLang;
    	}
    
    	public List&lt;String&gt; getSubtitleLang(){
    		return subtitleLang;
    	}
    
    	public void setGenres(List&lt;GenresItem&gt; genres){
    		this.genres = genres;
    	}
    
    	public List&lt;GenresItem&gt; 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&lt;String&gt; languages){
    		this.languages = languages;
    	}
    
    	public List&lt;String&gt; 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&lt;String&gt; tags){
    		this.tags = tags;
    	}
    
    	public List&lt;String&gt; getTags(){
    		return tags;
    	}
    
    	public void setChannels(List&lt;ChannelsItem&gt; channels){
    		this.channels = channels;
    	}
    
    	public List&lt;ChannelsItem&gt; 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 
    			&quot;AssetDetails{&quot; + 
    			&quot;asset_subtype = &#39;&quot; + assetSubtype + &#39;\&#39;&#39; + 
    			&quot;,audio_languages = &#39;&quot; + audioLanguages + &#39;\&#39;&#39; + 
    			&quot;,subtitle_languages = &#39;&quot; + subtitleLanguages + &#39;\&#39;&#39; + 
    			&quot;,rating = &#39;&quot; + rating + &#39;\&#39;&#39; + 
    			&quot;,description = &#39;&quot; + description + &#39;\&#39;&#39; + 
    			&quot;,title = &#39;&quot; + title + &#39;\&#39;&#39; + 
    			&quot;,drm_key_id = &#39;&quot; + drmKeyId + &#39;\&#39;&#39; + 
    			&quot;,extended = &#39;&quot; + extended + &#39;\&#39;&#39; + 
    			&quot;,duration = &#39;&quot; + duration + &#39;\&#39;&#39; + 
    			&quot;,episode_number = &#39;&quot; + episodeNumber + &#39;\&#39;&#39; + 
    			&quot;,video_url = &#39;&quot; + videoUrl + &#39;\&#39;&#39; + 
    			&quot;,subtitle_lang = &#39;&quot; + subtitleLang + &#39;\&#39;&#39; + 
    			&quot;,genres = &#39;&quot; + genres + &#39;\&#39;&#39; + 
    			&quot;,business_type = &#39;&quot; + businessType + &#39;\&#39;&#39; + 
    			&quot;,asset_type = &#39;&quot; + assetType + &#39;\&#39;&#39; + 
    			&quot;,tvshow = &#39;&quot; + tvshow + &#39;\&#39;&#39; + 
    			&quot;,season = &#39;&quot; + season + &#39;\&#39;&#39; + 
    			&quot;,id = &#39;&quot; + id + &#39;\&#39;&#39; + 
    			&quot;,skip_available = &#39;&quot; + skipAvailable + &#39;\&#39;&#39; + 
    			&quot;,cover_image = &#39;&quot; + coverImage + &#39;\&#39;&#39; + 
    			&quot;,slug = &#39;&quot; + slug + &#39;\&#39;&#39; + 
    			&quot;,season_details = &#39;&quot; + seasonDetails + &#39;\&#39;&#39; + 
    			&quot;,original_title = &#39;&quot; + originalTitle + &#39;\&#39;&#39; + 
    			&quot;,is_drm = &#39;&quot; + isDrm + &#39;\&#39;&#39; + 
    			&quot;,languages = &#39;&quot; + languages + &#39;\&#39;&#39; + 
    			&quot;,list_image = &#39;&quot; + listImage + &#39;\&#39;&#39; + 
    			&quot;,age_rating = &#39;&quot; + ageRating + &#39;\&#39;&#39; + 
    			&quot;,orderid = &#39;&quot; + orderid + &#39;\&#39;&#39; + 
    			&quot;,image_url = &#39;&quot; + imageUrl + &#39;\&#39;&#39; + 
    			&quot;,end_credits_start_s = &#39;&quot; + endCreditsStartS + &#39;\&#39;&#39; + 
    			&quot;,content_owner = &#39;&quot; + contentOwner + &#39;\&#39;&#39; + 
    			&quot;,tags = &#39;&quot; + tags + &#39;\&#39;&#39; + 
    			&quot;,channels = &#39;&quot; + channels + &#39;\&#39;&#39; + 
    			&quot;,web_url = &#39;&quot; + webUrl + &#39;\&#39;&#39; + 
    			&quot;,release_date = &#39;&quot; + releaseDate + &#39;\&#39;&#39; + 
    			&quot;}&quot;;
    		}
    }

In the above JSON season_details can be a JSONObject or empty.

答案1

得分: 0

你可以使用自定义的反序列化器来检查值是否为实际对象,并在其不是实际对象时决定如何处理。

例如(可用于任何类型):

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 中进行注册,请参阅此帖子

英文:

You can use custom deserializer to inspect if the value is a real object and decide what to do if it is not.

For example (to be used for any type):

public class StringOrObjectDeSerializer&lt;T&gt; implements JsonDeserializer&lt;T&gt; {
	// 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;
	}
}

Just register it before using, like:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(SeasonDetail.class, new StringOrObjectDeSerializer&lt;&gt;())
    .create();

If you need to know how to register it with Retrofit, see this post

huangapple
  • 本文由 发表于 2020年7月27日 22:22:26
  • 转载请务必保留本文链接:https://java.coder-hub.com/63117366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定