预期BEGIN_OBJECT但是使用自定义TypeAdapter进行STRING

时间:2015-07-02 00:31:36

标签: java android gson retrofit

所以我正在尝试使用Gson和Retrofit解决我的自定义TypeAdapter问题。我一直收到Dog错误,但我不确定如何解决它。以前我收到Expected BEGIN_OBJECT but was STRING错误,我解决了这个问题。我不确定它是否需要与这个新错误相同。我在下面列出了我的课程,感谢任何帮助。这就是我的json在这里的样子:http://pastie.org/private/bfo86iznldacbz10rtsdsg主要问题是json中的多媒体字段。如果没有值,它是一个空字符串,但如果有值,则返回包含jsonobjects的jsonarray。

ArrayAdapter.java

Expected BEGIN_ARRAY but was STRING

ArraryAdapterFactory

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;


public class ArrayAdapter<T> extends TypeAdapter<List<T>> {
    private Class<T> adapterclass;

    public ArrayAdapter(Class<T> adapterclass) {
        this.adapterclass = adapterclass;
    }

    public List<T> read(JsonReader reader) throws IOException {

        List<T> list = new ArrayList<T>();

        Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(new ArrayAdapterFactory())
                .create();

        if (reader.peek() == JsonToken.STRING) {
            T inning = gson.fromJson(reader, adapterclass);
            list.add(inning);
        } else if (reader.peek() == JsonToken.BEGIN_ARRAY) {

            reader.beginArray();
            while (reader.hasNext()) {
                T inning = gson.fromJson(reader, adapterclass);
                list.add(inning);
            }
            reader.endArray();

        } else if (reader.peek() == JsonToken.BEGIN_OBJECT) {
            reader.beginObject();
            while(reader.hasNext()) {
            }
        }

        return list;
    }

    public void write(JsonWriter writer, List<T> value) throws IOException {

    }

}

Times.java

import java.lang.reflect.ParameterizedType;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;

public class ArrayAdapterFactory implements TypeAdapterFactory {

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {

        TypeAdapter<T> typeAdapter = null;

        try {
            if (type.getRawType() == List.class)
                typeAdapter = new ArrayAdapter(
                        (Class) ((ParameterizedType) type.getType())
                                .getActualTypeArguments()[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return typeAdapter;


    }

}

POJO课程

News.java

public class NYTimes {

    // uses the new york times api
    // gets the top stores on the nytimes homepage
    private static final String API_URL = "http://api.nytimes.com/svc/news/v3/content/all/all";

    static Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();

    private static final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
            .setConverter(new GsonConverter(gson))
            .setEndpoint(API_URL)
            .build();

    private static final NYTimesService SERVICE = REST_ADAPTER.create(NYTimesService.class);

    public static NYTimesService getService() {
        return SERVICE;
    }
}

Result.java

public class News {

    @Expose
    private String status;
    @Expose
    private String copyright;
    @SerializedName("num_results")
    @Expose
    private Integer numResults;
    @Expose
    private List<Result> results = new ArrayList<Result>();

    /**
     *
     * @return
     * The status
     */
    public String getStatus() {
        return status;
    }

    /**
     *
     * @param status
     * The status
     */
    public void setStatus(String status) {
        this.status = status;
    }

    /**
     *
     * @return
     * The copyright
     */
    public String getCopyright() {
        return copyright;
    }

    /**
     *
     * @param copyright
     * The copyright
     */
    public void setCopyright(String copyright) {
        this.copyright = copyright;
    }

    /**
     *
     * @return
     * The numResults
     */
    public Integer getNumResults() {
        return numResults;
    }

    /**
     *
     * @param numResults
     * The num_results
     */
    public void setNumResults(Integer numResults) {
        this.numResults = numResults;
    }

    /**
     *
     * @return
     * The results
     */
    public List<Result> getResults() {
        return results;
    }

    /**
     *
     * @param results
     * The results
     */
    public void setResults(List<Result> results) {
        this.results = results;
    }

}

Multimedium.java

public class Result {
    @Expose
    private String section;
    @Expose
    private String subsection;
    @Expose
    private String title;
    @SerializedName("abstract")
    @Expose
    private String _abstract;
    @Expose
    private String url;
    @Expose
    private String byline;
    @SerializedName("thumbnail_standard")
    @Expose
    private String thumbnailStandard;
    @SerializedName("item_type")
    @Expose
    private String itemType;
    @Expose
    private String source;
    @SerializedName("updated_date")
    @Expose
    private String updatedDate;
    @SerializedName("created_date")
    @Expose
    private String createdDate;
    @SerializedName("published_date")
    @Expose
    private String publishedDate;
    @SerializedName("material_type_facet")
    @Expose
    private String materialTypeFacet;
    @Expose
    private String kicker;
    @Expose
    private String subheadline;
    @SerializedName("des_facet")
    @Expose
    private List<String> desFacet = new ArrayList<>();
    @SerializedName("org_facet")
    @Expose
    private List<String> orgFacet = new ArrayList<>();
    @SerializedName("per_facet")
    @Expose
    private List<String> perFacet = new ArrayList<>();
    @SerializedName("geo_facet")
    @Expose
    private List<String> geoFacet = new ArrayList<>();
    @SerializedName("related_urls")
    @Expose
    private Object relatedUrls;
    @Expose
    private List<Multimedium> multimedia;

    /**
     *
     * @return
     * The section
     */
    public String getSection() {
        return section;
    }

    /**
     *
     * @param section
     * The section
     */
    public void setSection(String section) {
        this.section = section;
    }

    /**
     *
     * @return
     * The subsection
     */
    public String getSubsection() {
        return subsection;
    }

    /**
     *
     * @param subsection
     * The subsection
     */
    public void setSubsection(String subsection) {
        this.subsection = subsection;
    }

    /**
     *
     * @return
     * The title
     */
    public String getTitle() {
        return title;
    }

    /**
     *
     * @param title
     * The title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     *
     * @return
     * The _abstract
     */
    public String getAbstract() {
        return _abstract;
    }

    /**
     *
     * @param _abstract
     * The abstract
     */
    public void setAbstract(String _abstract) {
        this._abstract = _abstract;
    }

    /**
     *
     * @return
     * The url
     */
    public String getUrl() {
        return url;
    }

    /**
     *
     * @param url
     * The url
     */
    public void setUrl(String url) {
        this.url = url;
    }

    /**
     *
     * @return
     * The byline
     */
    public String getByline() {
        return byline;
    }

    /**
     *
     * @param byline
     * The byline
     */
    public void setByline(String byline) {
        this.byline = byline;
    }

    /**
     *
     * @return
     * The thumbnailStandard
     */
    public String getThumbnailStandard() {
        return thumbnailStandard;
    }

    /**
     *
     * @param thumbnailStandard
     * The thumbnail_standard
     */
    public void setThumbnailStandard(String thumbnailStandard) {
        this.thumbnailStandard = thumbnailStandard;
    }

    /**
     *
     * @return
     * The itemType
     */
    public String getItemType() {
        return itemType;
    }

    /**
     *
     * @param itemType
     * The item_type
     */
    public void setItemType(String itemType) {
        this.itemType = itemType;
    }

    /**
     *
     * @return
     * The source
     */
    public String getSource() {
        return source;
    }

    /**
     *
     * @param source
     * The source
     */
    public void setSource(String source) {
        this.source = source;
    }

    /**
     *
     * @return
     * The updatedDate
     */
    public String getUpdatedDate() {
        return updatedDate;
    }

    /**
     *
     * @param updatedDate
     * The updated_date
     */
    public void setUpdatedDate(String updatedDate) {
        this.updatedDate = updatedDate;
    }

    /**
     *
     * @return
     * The createdDate
     */
    public String getCreatedDate() {
        return createdDate;
    }

    /**
     *
     * @param createdDate
     * The created_date
     */
    public void setCreatedDate(String createdDate) {
        this.createdDate = createdDate;
    }

    /**
     *
     * @return
     * The publishedDate
     */
    public String getPublishedDate() {
        return publishedDate;
    }

    /**
     *
     * @param publishedDate
     * The published_date
     */
    public void setPublishedDate(String publishedDate) {
        this.publishedDate = publishedDate;
    }

    /**
     *
     * @return
     * The materialTypeFacet
     */
    public String getMaterialTypeFacet() {
        return materialTypeFacet;
    }

    /**
     *
     * @param materialTypeFacet
     * The material_type_facet
     */
    public void setMaterialTypeFacet(String materialTypeFacet) {
        this.materialTypeFacet = materialTypeFacet;
    }

    /**
     *
     * @return
     * The kicker
     */
    public String getKicker() {
        return kicker;
    }

    /**
     *
     * @param kicker
     * The kicker
     */
    public void setKicker(String kicker) {
        this.kicker = kicker;
    }

    /**
     *
     * @return
     * The subheadline
     */
    public String getSubheadline() {
        return subheadline;
    }

    /**
     *
     * @param subheadline
     * The subheadline
     */
    public void setSubheadline(String subheadline) {
        this.subheadline = subheadline;
    }

    /**
     *
     * @return
     * The desFacet
     */
    public List<String> getDesFacet() {
        return desFacet;
    }

    /**
     *
     * @param desFacet
     * The des_facet
     */
    public void setDesFacet(List<String> desFacet) {
        this.desFacet = desFacet;
    }

    /**
     *
     * @return
     * The orgFacet
     */
    public List<String> getOrgFacet() {
        return orgFacet;
    }

    /**
     *
     * @param orgFacet
     * The org_facet
     */
    public void setOrgFacet(List<String> orgFacet) {
        this.orgFacet = orgFacet;
    }

    /**
     *
     * @return
     * The perFacet
     */
    public List<String> getPerFacet() {
        return perFacet;
    }

    /**
     *
     * @param perFacet
     * The per_facet
     */
    public void setPerFacet(List<String> perFacet) {
        this.perFacet = perFacet;
    }

    /**
     *
     * @return
     * The geoFacet
     */
    public List<String> getGeoFacet() {
        return geoFacet;
    }

    /**
     *
     * @param geoFacet
     * The geo_facet
     */
    public void setGeoFacet(List<String> geoFacet) {
        this.geoFacet = geoFacet;
    }

    /**
     *
     * @return
     * The relatedUrls
     */
    public Object getRelatedUrls() {
        return relatedUrls;
    }

    /**
     *
     * @param relatedUrls
     * The related_urls
     */
    public void setRelatedUrls(Object relatedUrls) {
        this.relatedUrls = relatedUrls;
    }

    /**
     *
     * @return
     * The multimedia
     */
    public List<Multimedium> getMultimedia() {
        return multimedia;
    }

    /**
     *
     * @param multimedia
     * The multimedia
     */
    public void setMultimedia(List<Multimedium> multimedia) {
        this.multimedia = multimedia;
    }
}

我知道要通过很多代码,但我正在寻找任何帮助来解决这个问题,所以我想尽可能地清楚。

1 个答案:

答案 0 :(得分:1)

我能够通过实施自定义JsonDeserializer然后将其添加到RestAdapter来获得解决方案,如下所示:

public class ResultsDeserializerJson implements JsonDeserializer<Result> {

@Override
    public Result deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        JsonElement titleElement = json.getAsJsonObject().get("title");
        JsonElement multimediaElement = json.getAsJsonObject().get("multimedia");
        if (multimediaElement.isJsonArray()) {
            return new Result(
                titleElement.toString(),
                (Multimedia[]) context.deserialize(multimediaElement.getAsJsonArray(), Multimedia[].class));
        } else if (multimediaElement.getAsString().equals("")) {
            Multimedia multimedia = new Multimedia();
            multimedia.setFormat("");
            multimedia.setUrl("");
            return new Result(titleElement.toString(), multimedia);
        } else {
            Log.d("ResultsDeserializerJson", multimediaElement.toString());
            throw new JsonParseException("Unsupported type of multimedia element");
        }
    }
}

Result.java内部我添加了以下构造函数(请注意,您可以为section,subsection等添加更多参数):

public Result(String title, Multimedia ... multimedia) {
    this.mTitle = title.replace("\"", "");;
    mMultimedia = Arrays.asList(multimedia);
}

然后我的RestAdapter执行以下操作:

private NYTimesService() {

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Result.class, new ResultsDeserializerJson()).create();

    mAsyncRestAdapter = new RestAdapter.Builder()
            .setEndpoint(API_URL)
            .setConverter(new GsonConverter(gson))
            .setRequestInterceptor(new RequestInterceptor() {
                @Override
                public void intercept(RequestFacade request) {
                    request.addEncodedQueryParam("api-key", API_KEY);
                }
            })
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .build();
}

我创建了一个自定义应用程序以使其正常工作,并且存储库在这里是开源的:

SampleNYTimesApp Repo

这仍然是一个hackish解决方案,我觉得它不是最优的,但我能够在我找到解决方案时得到以下内容:

enter image description here