Comments 18
Неплохо было бы добавить в статью сравнительные бенчмарки.
return "null";
Действительно, почему бы вместо чего-то подобного null'у не вернуть строку "null", ведь давно известно, что из-за этого не случится ничего плохого (нет, https://youtu.be/_c1am8NSx_s)
Это было бы валидно для toString (если toString'ом предлагается этот объект сериализовывать обратно в json, но тогда у всех остальных типов toString вернёт не валидный json), но для getValue это прямо совсем не подходящий вариант.
Поскольку данный парсер ожидает в качестве корневого элемента объект, а не массив
Валидный json может быть не только объектом или массивом, но и любым примитивным типом.
Да, тут взято подмножество валидного json. В RFC указано, что помимо объекта, валидным может быть любое значение (массив, строка, число, true, false, null). да и в статье написано, что API-возвращают json-массивы и парсер этого не умеет.
Добавил в конце, как сделать так, чтобы парсер обрабатывал правильно любое значение, являющееся JSON (но только ровно одно).
Вообще есть много вопросов, начиная с банальных, например, зачем считать в JsonArray count отдельно, хотя можно взять от листа, причём там судя по всему ошибка в setElements, полагаю, надо бы и счётчик обновить.
Заканчивая тем, насколько это вообще будет работать. Если цель была в том, чтобы потренироваться в написании статей — тогда понятно, тренируйтесь дальше. А так сыро, трудночитаемо, и не очень полезно
Тоже писал мини-парсер для своих нужд, но только он получился еще компактнее:
https://github.com/AlmazKo/microjson
Использую его, когда нужна работа с json без биндинга. В больших проектах, конечно лучше брать что-то типа Jackson'a
Ну, во-первых, у вас в методе экземпляра класса Json parseValue() Вы не проверяете литералы true, false, null, а сразу перематываете на нужное число символов, полагаясь на первую букву, хотя это может быть другим словом, на букву t, например, "topa", что сразу не соответствует JSON. Во-вторых, в методе parseObject не учитывается грамматически-правильная последовательность, в том смысле, что после чтения ключа (имени свойства) в строке может идти '}', что нарушает последовательность (ожидался символ ':'
). Т.е. по строке "{ "dummy" }"
вернётся пустой JSON-объект, а должно быть сообщение об ошибке "ожидался ':' а получили сразу '}'"
. (указали в описании репы fail-fast parser). Ссылка
Под заголовком "Состояния парсера" было бы хорошо разместить схему (конечный автомат?) состояний парсера. Я, например, заглянул за общим принципом реализации, а не за деталями в коде, поэтому слегка разочарован.
P.S. И вообще, реализация в коде объектов - типов данных просится под кат.
Сразу видно - человеку нечем заняться. Мне бы столько свободного времени. Надеюсь, этот велосипед не попадёт ни в какой крупный проект, иначе команде не позавидуешь.
PS: Автотесты-то хоть есть? Или совсем всё плохо?
А разве не надо для массивов тоже использовать дженерики в этом случае? А то получается что в конечном итоге, получив из массива объект, нужно будет кастить его тип?
Т.е.
public class JsonArray extends JsonElement<List<JsonElement>>
нужно заменить на что-то типа
public class JsonArray<TT> extends JsonElement<List<JsonElement<TT>>>
Или нет?
В Вашем случае всё равно придётся кастить в тип, поскольку JsonObject по строковому ключу извлекает значение в виде JsonElement. Да и при обработке тоже. В стэке ведь могут быть массивы содержащие различные подтипы JsonElement.
Че то мне лень вникать, но почему объекты из массива по строковому ключу извлекаются?
А то, что в массиве могут содержаться объекты разных типов это по моему вообще нарушение сути понятия "массив".
Зачем вообще тогда тут городить огород с дженериками если конечному пользователю все равно кастить? Да еще и так опасно.
Да, понятие "массив" неккоректно здесь использовать. Правильное понятие - "список". Но само понятие тянется из того же RFC 8259 (везде указано "array").
По строкову ключу извлекается значение из объекта. Значение уже может быть массивом, или тем же объектом по типу.
А дженерик здесь для getValue() из JsonElement. Но Java не C#. В рантайме у нас всё стирается, и остаётся Object. Поэтому нельзя писать T a = new T()
. А в C# можно, при условии, что параметр тип T имеет конструктор. Указывается через ограничение where T : new()
Yet another JSON-парсер