代码之家  ›  专栏  ›  技术社区  ›  Crushinz

gson在需要对象时遇到空数组问题

  •  1
  • Crushinz  · 技术社区  · 6 年前

    我试图使用gson处理json文件,但遇到了一个奇怪的错误。我从中读取的json(无法修改)有一种处理空字段的奇怪方式。它将[]放在没有数据的地方,使gson在需要对象时认为它是一个数组。

    gson的一个示例:

    //non-empty field
    "prizes":[
                {
                    "year":"1902",
                    "category":"physics",
                    "share":"2",
                    "motivation":"\"in recognition of the extraordinary service they rendered by their researches into the influence of magnetism upon radiation phenomena\"",
                    "affiliations":[
                        {
                            "name":"Leiden University",
                            "city":"Leiden",
                            "country":"the Netherlands"
                        }
                    ]
                }
            ]
    
    //empty field
    "prizes":[
                {
                    "year":"1903",
                    "category":"physics",
                    "share":"4",
                    "motivation":"\"in recognition of the extraordinary services they have rendered by their joint researches on the radiation phenomena discovered by Professor Henri Becquerel\"",
                    "affiliations":[
                        []
                    ]
                }
            ]
    

    这是我处理json的代码:

    public static void main(String[] args) throws IOException {
        // Get Gson object
        Gson gson = new Gson();
    
        // read JSON file data as String
        String fileData = new 
        String(Files.readAllBytes(Paths.get("laureates.json")));
    
        // parse json string to object
        Example laur = gson.fromJson(fileData, Example.class);
    
        // print object data
        System.out.println("\n\nLaureates Object\n\n" + laur);
    }
    

    我已经安排好了所有的课程,我相信一旦这个问题得到解决,它就会起作用。 我得到的错误是“应为BEGIN\u对象,但在第1行第3401列为BEGIN\u数组”(第3401列是第一个[]的确切位置)

    3 回复  |  直到 6 年前
        1
  •  0
  •   Eduardo Folly    6 年前

    设置空对象的正确方法是不使用括号。你知道的。:-)

    "prizes":[
            {
                "year":"1903",
                "category":"physics",
                "share":"4",
                "motivation":"\"in recognition of the extraordinary services they have rendered by their joint researches on the radiation phenomena discovered by Professor Henri Becquerel\"",
                "affiliations":[
                ]
            }
        ]
    

    您可以采取一种解决方法来移除支架。

    fileData = fileData.replaceAll("\\[]", "");
    

    我希望这有帮助。

        2
  •  0
  •   nyulan    6 年前

    看起来gson需要一个对象,但返回了数组 尝试将示例更改为数组,如下所示。

    Example[] emps= gson.fromJson(yourJson, Example
    [].class);
    

    另请参见相关 GSON throwing "Expected BEGIN_OBJECT but was BEGIN_ARRAY"?

        3
  •  0
  •   Lyubomyr Shaydariv    6 年前

    您总是可以使用类型适配器来适应设计糟糕但格式良好的JSON文档。例如,以下类型适配器修复了您的案例:

    final class EmptyListFixTypeAdapterFactory
            implements TypeAdapterFactory {
    
        private static final TypeAdapterFactory instance = new EmptyListFixTypeAdapterFactory();
    
        private EmptyListFixTypeAdapterFactory() {
        }
    
        static TypeAdapterFactory get() {
            return instance;
        }
    
        @Override
        public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
            // If it's not a list, then just let Gson pass through the rest of the type adapters chain
            if ( !List.class.isAssignableFrom(typeToken.getRawType()) ) {
                return null;
            }
            // Get the original List adapter - we'll use it below
            @SuppressWarnings("unchecked")
            final TypeAdapter<List<Object>> delegateTypeAdapter = (TypeAdapter<List<Object>>) gson.getDelegateAdapter(this, typeToken);
            // Wrap it
            @SuppressWarnings("unchecked")
            final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) EmptyListFixTypeAdapter.get(delegateTypeAdapter);
            return typeAdapter;
        }
    
        private static final class EmptyListFixTypeAdapter<E>
                extends TypeAdapter<List<E>> {
    
            // JsonParser as of Gson 2.8.2 holds no state
            private static final JsonParser jsonParser = new JsonParser();
    
            private final TypeAdapter<List<E>> delegateTypeAdapter;
    
            private EmptyListFixTypeAdapter(final TypeAdapter<List<E>> delegateTypeAdapter) {
                this.delegateTypeAdapter = delegateTypeAdapter;
            }
    
            private static <E> TypeAdapter<List<E>> get(final TypeAdapter<List<E>> delegateTypeAdapter) {
                return new EmptyListFixTypeAdapter<>(delegateTypeAdapter)
                        .nullSafe(); // A convenient method to add null-checking automatically
            }
    
            @Override
            public void write(final JsonWriter out, final List<E> value)
                    throws IOException {
                // In case if you need to produce document with this quirks
                if ( value.isEmpty() ) {
                    out.beginArray();
                    out.beginArray();
                    out.endArray();
                    out.endArray();
                    return;
                }
                delegateTypeAdapter.write(out, value);
            }
    
            @Override
            public List<E> read(final JsonReader in) {
                final JsonElement jsonElement = jsonParser.parse(in);
                final JsonArray array = jsonElement.getAsJsonArray();
                // Is it [[]]?
                if ( array.size() == 1 ) {
                    final JsonElement element = array.get(0);
                    if ( element.isJsonArray() && ((JsonArray) element).size() == 0 ) {
                        // Yes, detected
                        return new ArrayList<>();
                    }
                }
                // No, proceed with the delegate type adapter
                return delegateTypeAdapter.fromJsonTree(array);
            }
    
        }
    
    }
    

    现在假设您有以下映射:

    final class Laureate {
        final List<Prize> prizes = new ArrayList<>();
    }
    
    final class Prize {
        final int year = Integer.valueOf(0);
        final String category = null;
        final List<Affiliation> affiliations = new ArrayList<>();
    }
    
    final class Affiliation {
        final String name = null;
        final String city = null;
        final String country = null;
    }
    

    然后:

    private static final Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(EmptyListFixTypeAdapterFactory.get())
            .create();
    
    private static final Type laureatesType = new TypeToken<List<Laureate>>() {
    }.getType();
    
    public static void main(final String... args)
            throws IOException {
        try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q49603826.class, "laureates.json") ) {
            gson.<List<Laureate>>fromJson(jsonReader, laureatesType)
                    .stream()
                    .flatMap(laureate -> laureate.prizes.stream())
                    .peek(prize -> System.out.println("Prize: " + prize.year + " " + prize.category))
                    .flatMap(prize -> prize.affiliations.stream())
                    .peek(affiliation -> System.out.println("\tAffiliation: " + affiliation.name + " " + affiliation.city + " " + affiliation.country))
                    .forEach(affiliation -> {
                    });
        }
    }
    

    输出:

    奖项:1902年物理学
    。。。。。。。。附属机构:荷兰莱顿莱顿大学
    奖项:1903年物理学