#java #arrays #json
#java #массивы #json
Вопрос:
Я использую эту библиотеку: https://github.com/jdereg/json-io
Это упрощенный пример того, что я пытаюсь сделать, чтобы воспроизвести ошибку:
import com.cedarsoftware.util.io.JsonReader;
Map args = new HashMap();
args.put(JsonReader.USE_MAPS, true);
List<String> a = (List<String>)JsonReader.jsonToJava("["1.1","1.2"]", args);
Во время выполнения это выдает:
java.lang.ClassCastException: класс [Ljava.lang.Объект; не может быть приведен к классу java.util.Список ([Ljava.lang.Object; и java.util.Список находится в модуле java.base загрузчика ‘bootstrap’)
В качестве альтернативы, args
можно исключить (удалить две средние строки и args
аргумент jsonToJava
) с тем же эффектом.
Чтение словарей / карт работает нормально, например, этот код выводит «example», как и ожидалось:
Map<String,Object> fields = (Map<String,Object>)JsonReader.jsonToJava("{"example":true}");
for (Map.Entry<String,Object> field : fields.entrySet()) {
System.out.println(field.getKey());
}
Я не могу понять, как читать только массивы. Документация, которую я смог найти для библиотеки, довольно лаконична и не показывает пример этого. Отслеживая исходный код, чтобы увидеть, какого рода объект это должен быть, я в конечном итоге нахожусь в функции с именем readArray, где она использует ArrayList внутренне: https://github.com/jdereg/json-io/blob/master/src/main/java/com/cedarsoftware/util/io/JsonParser.java#L280 . Похоже, то, что я делаю, должно быть приведено к списку (я также пробовал ArrayList, чтобы быть уверенным).
Комментарии:
1. Первая строка не похожа на json, вы пробовали
"{"array": ["1.1","1.2"]}"
?2.
[Ljava.lang.Object;
это массив из,Object
поэтому попробуйте привести кObject[]
и обрабатывать элементы в массиве по отдельности. Почему это неString[]
массив? Поскольку массивы Json могут содержать что угодно, и анализатор json не знает тип элементов, пока все они не будут проанализированы (но ему нужно было бы хранить их где-нибудь во время синтаксического анализа, так чтоObject
это самый простой в использовании тип — более сложный анализатор мог бы проверить тип всех элементов и соответствующим образом построить результирующий массив, но это требует немалых усилий для получения небольшой отдачи, поскольку вам все равно пришлось бы знать тип и выполнять приведение).3. @JoakimDanielson Да, у меня есть, я удалил объект переноса для упрощения. Насколько я могу судить, json.org не говорит, что сообщение JSON должно начинаться с
{
. Он также отлично разбирается в nodejs сJSON.parse(str)
. Но я попытался, потому что я также не был уверен, нужно ли его переносить, и это не имело никакого значения. Если я заменяю значение «true» элемента «example» второго фрагмента кода, я получаю ту же проблему.4. @Thomas Спасибо за предложение! Я попробую это завтра на работе и отчитаюсь.
5. @Thomas прав.
Object[]
возвращается массив. Если вы хотите иметь контроль над процессом десериализации и предоставить ожидаемый тип, используйтеJackson
илиGson
библиотеку.
Ответ №1:
java.lang.ClassCastException: класс [Ljava.lang.Объект; не может быть приведен к классу java.util.Список
Обратите внимание, что [Ljava.lang.Object
представляет тип массива для массивов объектов, так оно и есть Object[]
. Поскольку массивы json могут содержать что угодно, то есть строки, логические значения, числа, объекты или массивы, и в любой комбинации любой анализатор JSON будет иметь 3 варианта:
- Используйте
Object
в качестве типа элемента массива. Тогда это привело бы кObject[]
как в вашем случае. - Используйте некоторый тип элемента массива, предоставленный пользователем, т. Е. Если вы знаете, что массив будет содержать только строки, тогда вы бы сказали анализатору, что он должен выдать
String[]
результат. Если массив содержит что-либо, кроме строк, это, скорее всего, приведет к сбою. - Сложный анализатор мог бы сначала собрать элементы, определить их типы и попытаться использовать наиболее специальные распространенные типы (если все элементы являются строками, которые были бы
String
). Однако API не может отразить это, потому что компилятор не знает, что будет содержать json во время выполнения. Следовательно, API может использовать только первые два параметра (во многих библиотеках, таких как Jackon или Gson, присутствуют оба), поэтому пользователю затем придется приводить либо массив, либо сами элементы, и в этом случае мало что можно сделать, чтобы сделать анализатор настолько сложным.
Теперь вы, вероятно, спросите, почему анализатор возвращает Object[]
вместо List<Object>
. Это решение, принятое разработчиками этой библиотеки, и я могу только догадываться, каковы причины. Однако сам json знает только массивы, поэтому логическим следствием было бы также использовать Java-массивы, если не предоставлена другая информация о типе.
Комментарии:
1. »
[Ljava.lang.Object
представляет тип массива для массивов объектов » Чтобы уточнить, если бы это был просто объект (не массив), ошибка содержала быLjava.lang.Object
без[
? Вот как вы могли бы определить, в чем была проблема?2. @Luc вывод (тип) для
Object
был быjava.lang.Object
, тип дляString[]
был бы[Ljava.lang.String
— so[L
указывает массив следующего типа (в случае классов или интерфейсов). Смотрите здесь для получения дополнительной информации: docs.oracle.com/javase/tutorial/reflect/special /… . В основном полученный вами результат определяетсяClass.getName()
Ответ №2:
Чтобы расширить отличный ответ Томаса, вот решение для удобочитаемого json:
Преобразовать список объектов в json:
public String toJSONList(List<Foo> fooList) {
Map<String, Object> args = new HashMap<>();
args.put(JsonWriter.PRETTY_PRINT, true); // just to make sure it looks good
args.put(JsonWriter.TYPE, false); //disable ugly @type properties
return JsonWriter.objectToJson(fooList, args);
}
Он генерирует приятный для чтения человеком json со списком:
[
{
"id":100,
"name":"John"
},
{
"id":101,
"name":"Tirion"
}
]
Преобразуйте приведенный выше json обратно в List
public List<Foo> fromJSONList(String json) {
Map<String, Object> args = new HashMap<>();
args.put(JsonReader.USE_MAPS, true);
JsonReader jsonReader = new JsonReader();
List<Foo> result = new ArrayList<>();
Object[] array = (Object[])JsonReader.jsonToJava(json, args);
for (int i=0; i<array.length; i ) {
//we need to tell what is the type (remember that we have removed it above?)
((Map)array[i]).put("@type", "com.something.model.Foo");
Foo foo =(Foo)jsonReader.jsonObjectsToJava((JsonObject) array[i]);
result.add(foo);
}
return resu<
}