Удаление десериализации массива json с использованием gson

Продолжая этот вопрос.

У меня возникли проблемы с десериализацией следующего массива json (Извините за размер):

"geometry": { "type": "Polygon", "coordinates": [ [ [ 771230.894373, 4422896.962001 ],
 [ 804804.852796, 4451159.130080 ], [ 876828.563339, 4417873.954498 ], [ 959794.979827, 
4430944.287708 ], [ 910992.515063, 4372980.866944 ], [ 932488.308736, 4357684.778349 ], 
[ 918573.372386, 4115663.286966 ], [ 834059.614976, 4013708.358795 ], [ 929360.231044, 
3833522.241529 ], [ 1008029.715188, 3776446.653183 ], [ 1061663.445852, 3533717.758754      
], [ 1035703.740599, 3519308.069656 ], [ 1095348.723766, 3396028.487184 ], [ 
1108462.159782, 3230455.268230 ], [ 1083571.121640, 3163122.508021 ], [ 1103953.720405, 
3082716.041755 ], [ 1045722.494771, 3020215.642212 ], [ 1117367.719045, 2915275.458735 
], [ 1141268.013718, 2827405.304519 ], [ 1286729.192338, 2790314.754276 ], [ 
1334329.406601, 2695307.513404 ], [ 829417.592210, 2374337.277646 ], [ 647042.870444, 
2207530.090128 ], [ 370914.873531, 2152159.656850 ], [ 346669.488436, 2173360.227237 ], 
[ 359905.375891, 2251757.174668 ], [ 199905.871774, 2309591.361246 ], [ 129963.835709, 
2361036.252651 ], [ 130208.738589, 2404106.913263 ], [ -964785.432600, 3159802.671416 
], [ -964829.960396, 3338713.127631 ], [ -851005.781060, 3424742.002477 ], [ -
616522.405653, 3491025.523892 ], [ -547749.224241, 3569019.334331 ], [ -403724.067052, 
3628920.873754 ], [ -423973.082428, 3724062.779415 ], [ -333893.350478, 3741450.793542 
], [ -317696.364567, 3774909.265404 ], [ -131414.328674, 3777826.527844 ], [ -
112467.751341, 3830221.719769 ], [ -185682.580436, 3930014.456814 ], [ -194499.084106, 
4129581.855629 ], [ -245950.952751, 4175549.526399 ], [ -42303.076294, 4287174.981681 
], [ -11222.674464, 4271148.905617 ], [ 131633.628071, 4371332.547494 ], [ 
433220.392528, 4427574.250017 ], [ 593119.709103, 4389089.571176 ], [ 719645.442339, 
4451856.882422 ], [ 771230.894373, 4422896.962001 ] ] ] }

Если я вставляю его в json-viewer, я получаю эту структуру:

[geometry]
...
[coordinates] => Array
    (
        [0] => Array
            (
                [0] => Array
                    (
                        [0] => 771230.894373
                        [1] => 4422896.962001
                    )
                [1] => Array
                    (
                        [0] => 804804.852796
                        [1] => 4451159.13008
                    )
                ...
                [n] => Array
        [n] => Array

Теперь массив, содержащий массивы с координатами, имеет переменный размер. Поэтому я понял, что в java весь этот объект будет массивом, содержащим набор массивов, причем каждый массив содержит Collection<double[]>. Что-то вроде Collection<double[]>[][].

Но gson этого не принимает. Появляется следующее сообщение об ошибке:

Exception in thread "main" com.google.gson.JsonParseException: Expecting object but     
found array: 2.963610

Что кажется странным, поскольку 2.963610 не выглядит как массив для меня. Но это, возможно, смутило меня до такой степени, что я потерял, более или менее...

Ответ 1

Я думаю, что знаю, откуда возникла ваша проблема, прочитав Gson API:

Если объект, который у вас есть, сериализация/десериализация - это Параметрированный тип (т.е. Содержит хотя бы один параметр типа и может быть массив), то вы должны использовать toJson (объект, тип) или fromJson (String, Type). Здесь пример для сериализации и десериализация параметра ParameterizedType:

Type listType = new TypeToken<LinkedList>() {}.getType();
List target = new LinkedList();
target.add("blah");

Gson gson = new Gson();
String json = gson.toJson(target, listType);
List target2 = gson.fromJson(json, listType);

Зная, что

Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType() 

Надеюсь, что это поможет.

Ответ 2

coordinates в JSON является трехмерной матрицей. С Collection<double[]>[][] вы слишком далеко продвигаетесь вперед. Сама Collection уже является одним измерением, поэтому вы в основном объявили четырехмерную матрицу.

С сообщением об ошибке Gson в основном говорит вам, что он ожидает объект для четвертого измерения, но вместо этого столкнулся с двойным.

Ниже представлены действительные трехмерные матрицы, которые должны отлично обрабатываться Gson:

  • private double[][][] coordinates; (рекомендуется)
  • private Collection<double[]>[] coordinates;
  • private Collection<double[][]> coordinates;
  • private Collection<Collection<double[]>> coordinates;
  • private Collection<Collection<Collection<Double>>> coordinates;

Тем не менее, я бы предпочел List выше Collection в данном конкретном случае. С помощью List вы можете гарантировать, что он заполнен порядком вставки, и вы сможете get по индексу.

Ответ 3

В соответствии с руководством пользователя Gson:

Сериализация и десериализация общих типов
Когда вы вызываете toJson (obj), Gson вызывает obj.getClass(), чтобы получить информацию о полях для сериализации. Аналогично, вы обычно можете передать объект MyClass.class в методе fromJson(json, MyClass.class). Это отлично работает, пока объект не является универсальным типом. Однако, если объект имеет общий тип, тогда общая информация типа теряется из-за Java Type Erasure. Вот пример, иллюстрирующий точку:

List<String> myStrings = new List<String>();
gson.toJson(myStrings); // Will cause a runtime exception

gson.fromJson(json, myStrings.getClass());

Вышеупомянутый вызов приводит к исключению во время выполнения, поскольку Gson вызывает myStrings.getClass(), чтобы получить информацию о своем классе, но этот метод возвращает исходный класс List.class. Это означает, что Gson не знает, что это список строк, а не простых объектов.

Вы можете решить эту проблему, указав правильный параметризованный тип для своего общего типа. Вы можете сделать это, используя класс TypeToken.

Type listType = new TypeToken<List<String>>() {}.getType();
gson.toJson(myStrings, listType);

gson.fromJson(json, listType);

Идиома, используемая для получения listType, фактически определяет анонимный локальный внутренний класс, содержащий метод getType(), который возвращает полностью параметризованный тип.

Надеюсь, что это поможет.

Ответ 4

Я думаю, нам понадобится более подробная информация, например, что вы написали для десериализации.