因错误而无法将json字符串转换为POJO预期字符串但是为BEGIN_ARRAY

时间:2017-02-25 07:47:43

标签: java json gson

出于某种原因,我无法将其转换为POJO。我正在尝试的电话是这样的:

NewsEntities  newsEntities = new Gson().fromJson(jsonString, NewsEntities.class);

神秘之处在于json不在数组中。我认为这是一个jsonObject。 jsonString为here

我在android中遇到的错误是:

    Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 1006 path $.results[0].org_facet
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err:     at com.google.gson.stream.JsonReader.nextString(JsonReader.java:831)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err:     at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:422)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err:     at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:410)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
02-24 23:42:49.956 15463-15531/news.myapp.com.technewssample W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(Reflect

newsEntities类本身看起来像这样,我只是从http://www.jsonschema2pojo.org/

创建
    public class NewsEntities implements Parcelable
{

    @SerializedName("status")
    @Expose
    private String status;
    @SerializedName("copyright")
    @Expose
    private String copyright;
    @SerializedName("section")
    @Expose
    private String section;
    @SerializedName("last_updated")
    @Expose
    private String lastUpdated;
    @SerializedName("num_results")
    @Expose
    private Integer numResults;
    @SerializedName("results")
    @Expose
    private List<Result> results = null;
    public final static Parcelable.Creator<NewsEntities> CREATOR = new Creator<NewsEntities>() {


        @SuppressWarnings({
            "unchecked"
        })
        public NewsEntities createFromParcel(Parcel in) {
            NewsEntities instance = new NewsEntities();
            instance.status = ((String) in.readValue((String.class.getClassLoader())));
            instance.copyright = ((String) in.readValue((String.class.getClassLoader())));
            instance.section = ((String) in.readValue((String.class.getClassLoader())));
            instance.lastUpdated = ((String) in.readValue((String.class.getClassLoader())));
            instance.numResults = ((Integer) in.readValue((Integer.class.getClassLoader())));
            in.readList(instance.results, (Result.class.getClassLoader()));
            return instance;
        }

        public NewsEntities[] newArray(int size) {
            return (new NewsEntities[size]);
        }

    }
    ;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getCopyright() {
        return copyright;
    }

    public void setCopyright(String copyright) {
        this.copyright = copyright;
    }

    public String getSection() {
        return section;
    }

    public void setSection(String section) {
        this.section = section;
    }

    public String getLastUpdated() {
        return lastUpdated;
    }

    public void setLastUpdated(String lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    public Integer getNumResults() {
        return numResults;
    }

    public void setNumResults(Integer numResults) {
        this.numResults = numResults;
    }

    public List<Result> getResults() {
        return results;
    }

    public void setResults(List<Result> results) {
        this.results = results;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(status);
        dest.writeValue(copyright);
        dest.writeValue(section);
        dest.writeValue(lastUpdated);
        dest.writeValue(numResults);
        dest.writeList(results);
    }

    public int describeContents() {
        return  0;
    }

    }

更新:这是结果类:

    public class Result implements Parcelable
{

    @SerializedName("section")
    @Expose
    private String section;
    @SerializedName("subsection")
    @Expose
    private String subsection;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("abstract")
    @Expose
    private String _abstract;
    @SerializedName("url")
    @Expose
    private String url;
    @SerializedName("byline")
    @Expose
    private String byline;
    @SerializedName("item_type")
    @Expose
    private String itemType;
    @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;
    @SerializedName("kicker")
    @Expose
    private String kicker;
    @SerializedName("des_facet")
    @Expose
    private List<String> desFacet = null;
    @SerializedName("org_facet")
    @Expose
    private String orgFacet;
    @SerializedName("per_facet")
    @Expose
    private String perFacet;
    @SerializedName("geo_facet")
    @Expose
    private List<String> geoFacet = null;
    @SerializedName("multimedia")
    @Expose
    private List<Multimedium> multimedia = null;
    public final static Parcelable.Creator<Result> CREATOR = new Creator<Result>() {


        @SuppressWarnings({
            "unchecked"
        })
        public Result createFromParcel(Parcel in) {
            Result instance = new Result();
            instance.section = ((String) in.readValue((String.class.getClassLoader())));
            instance.subsection = ((String) in.readValue((String.class.getClassLoader())));
            instance.title = ((String) in.readValue((String.class.getClassLoader())));
            instance._abstract = ((String) in.readValue((String.class.getClassLoader())));
            instance.url = ((String) in.readValue((String.class.getClassLoader())));
            instance.byline = ((String) in.readValue((String.class.getClassLoader())));
            instance.itemType = ((String) in.readValue((String.class.getClassLoader())));
            instance.updatedDate = ((String) in.readValue((String.class.getClassLoader())));
            instance.createdDate = ((String) in.readValue((String.class.getClassLoader())));
            instance.publishedDate = ((String) in.readValue((String.class.getClassLoader())));
            instance.materialTypeFacet = ((String) in.readValue((String.class.getClassLoader())));
            instance.kicker = ((String) in.readValue((String.class.getClassLoader())));
            in.readList(instance.desFacet, (java.lang.String.class.getClassLoader()));
            instance.orgFacet = ((String) in.readValue((String.class.getClassLoader())));
            instance.perFacet = ((String) in.readValue((String.class.getClassLoader())));
            in.readList(instance.geoFacet, (java.lang.String.class.getClassLoader()));
            in.readList(instance.multimedia, (Multimedium.class.getClassLoader()));
            return instance;
        }

        public Result[] newArray(int size) {
            return (new Result[size]);
        }

    }
    ;

    public String getSection() {
        return section;
    }

    public void setSection(String section) {
        this.section = section;
    }

    public String getSubsection() {
        return subsection;
    }

    public void setSubsection(String subsection) {
        this.subsection = subsection;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAbstract() {
        return _abstract;
    }

    public void setAbstract(String _abstract) {
        this._abstract = _abstract;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getByline() {
        return byline;
    }

    public void setByline(String byline) {
        this.byline = byline;
    }

    public String getItemType() {
        return itemType;
    }

    public void setItemType(String itemType) {
        this.itemType = itemType;
    }

    public String getUpdatedDate() {
        return updatedDate;
    }

    public void setUpdatedDate(String updatedDate) {
        this.updatedDate = updatedDate;
    }

    public String getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(String createdDate) {
        this.createdDate = createdDate;
    }

    public String getPublishedDate() {
        return publishedDate;
    }

    public void setPublishedDate(String publishedDate) {
        this.publishedDate = publishedDate;
    }

    public String getMaterialTypeFacet() {
        return materialTypeFacet;
    }

    public void setMaterialTypeFacet(String materialTypeFacet) {
        this.materialTypeFacet = materialTypeFacet;
    }

    public String getKicker() {
        return kicker;
    }

    public void setKicker(String kicker) {
        this.kicker = kicker;
    }

    public List<String> getDesFacet() {
        return desFacet;
    }

    public void setDesFacet(List<String> desFacet) {
        this.desFacet = desFacet;
    }

    public String getOrgFacet() {
        return orgFacet;
    }

    public void setOrgFacet(String orgFacet) {
        this.orgFacet = orgFacet;
    }

    public String getPerFacet() {
        return perFacet;
    }

    public void setPerFacet(String perFacet) {
        this.perFacet = perFacet;
    }

    public List<String> getGeoFacet() {
        return geoFacet;
    }

    public void setGeoFacet(List<String> geoFacet) {
        this.geoFacet = geoFacet;
    }

    public List<Multimedium> getMultimedia() {
        return multimedia;
    }

    public void setMultimedia(List<Multimedium> multimedia) {
        this.multimedia = multimedia;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeValue(section);
        dest.writeValue(subsection);
        dest.writeValue(title);
        dest.writeValue(_abstract);
        dest.writeValue(url);
        dest.writeValue(byline);
        dest.writeValue(itemType);
        dest.writeValue(updatedDate);
        dest.writeValue(createdDate);
        dest.writeValue(publishedDate);
        dest.writeValue(materialTypeFacet);
        dest.writeValue(kicker);
        dest.writeList(desFacet);
        dest.writeValue(orgFacet);
        dest.writeValue(perFacet);
        dest.writeList(geoFacet);
        dest.writeList(multimedia);
    }

    public int describeContents() {
        return  0;
    }

}

2 个答案:

答案 0 :(得分:1)

你还没有附加你的结果类,但它看起来像你的结果类有一个字符串字段而不是org_facet中的数组。但是,如果添加Result类,则更容易回答。

答案 1 :(得分:1)

自动POJO生成器在某些情况下可能会生成错误的映射,尤其是在映射字段是多态的情况下或出于任何原因使用非标准方法时。根据您获得的错误,您的映射需要String,但JSON在该位置有一个数组。在您的情况下,$.results[0].org_facet指向:

...,"org_facet":["Amazon.com Inc","Cravath Swaine \u0026 Moore"],...
             // ^____here

如果您将地图String orgFacet更改为List<String> orgFacet,则会为perFacetmultimedia等其他字段带来类似错误(周围还有更多)。由于这些字段是列表而""只是空数组[]null的标记,因此Gson无法处理它,因为这种消息格式。但是,您可以使用此类字段编写自定义类型适配器,该适配器适用于使用单个Gson实例反序列化的所有列表。

final class ArrayOrEmptyStringTypeAdapter<E>
        extends TypeAdapter<List<E>> {

    private final Gson gson;
    private final Type elementType;

    private ArrayOrEmptyStringTypeAdapter(final Gson gson, final Type elementType) {
        this.gson = gson;
        this.elementType = elementType;
    }

    static <E> TypeAdapter<List<E>> getArrayOrEmptyStringTypeAdapter(final Gson gson, final Type elementType) {
        return new ArrayOrEmptyStringTypeAdapter<>(gson, elementType);
    }

    @Override
    public void write(final JsonWriter out, final List<E> list) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<E> read(final JsonReader in)
            throws IOException {
        final JsonToken token = in.peek(); // Peek the next token
        switch ( token ) {
        case BEGIN_ARRAY: // If it's an array begin `[`, then parse it as an array
            return parseAsArray(in);
        case STRING: // Or if it's a string, parse it in another way
            return parseAsString(in);
        default:
            throw new MalformedJsonException("Unexpected token: " + token);
        }
    }

    private List<E> parseAsArray(final JsonReader in)
            throws IOException {
        final List<E> list = new ArrayList<>();
        in.beginArray(); // Consume `[` from the token stream
        while ( in.peek() != END_ARRAY ) {
            final E element = gson.fromJson(in, elementType); // Delegate downstream parsing to the Gson instance
            list.add(element);
        }
        in.endArray(); // Consume `]` from the token stream
        return list;
    }

    private List<E> parseAsString(final JsonReader in)
            throws IOException {
        in.skipValue(); // in.nextString() consumes more memory accumulating the result
        return new ArrayList<>(); // Or null -- up to you. Or even Collections.emptyList(), but Gson uses mutable lists so we do
    }

}

接下来是通过类型适配器工厂绑定类型适配器和Gson实例:

final class ArrayOrEmptyStringTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeAdapterFactory arrayOrEmptyStringTypeAdapterFactory = new ArrayOrEmptyStringTypeAdapterFactory();

    private ArrayOrEmptyStringTypeAdapterFactory() {
    }

    static TypeAdapterFactory getArrayOrEmptyStringTypeAdapterFactory() {
        return arrayOrEmptyStringTypeAdapterFactory;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        if ( List.class.isAssignableFrom(typeToken.getRawType()) ) { // Is it an instance of java.util.List? Not that getRawType() and getType() have different purposes
            final TypeAdapter<List<Object>> typeAdapter = getArrayOrEmptyStringTypeAdapter(gson, getListElementType(typeToken.getType()));
            @SuppressWarnings("unchecked")
            final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) typeAdapter;
            return castTypeAdapter;
        }
        return null;
    }

    private static Type getListElementType(final Type type) {
        return type instanceof ParameterizedType // Is it a generic type with type parameters?
                ? ((ParameterizedType) type).getActualTypeArguments()[0] // If yes, then we know that java.util.List has one type paremeter only
                : Object.class; // Otherwise it's a raw list, and no element type info is provided
    }

}

如何使用:

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(getArrayOrEmptyStringTypeAdapterFactory())
        .create();
final NewsEntities newEntities = gson.fromJson(jsonString, NewsEntities.class);
System.out.println(newEntities.results.get(0).orgFacet);
System.out.println(newEntities.results.get(0).perFacet)

输出:

  

[Amazon.com Inc,Cravath Swaine&amp;穆尔]
  [Bezos,Jeffrey P]

相关问题