Fix serializer recursion handling and bump version to 1.0.3#40
Fix serializer recursion handling and bump version to 1.0.3#40
Conversation
| private static class AccumulatingMigrator implements Migrator { | ||
|
|
||
| @Override | ||
| public <I, O> O migrate(I data, MigrationPoint mPoint, SerializerSpec<I, O> serializerSpec) { | ||
| return (O) (String.valueOf(data) + ((MigrationSpecImpl) mPoint.getMigrationSpec()).getSpec().replace("TEST", "")); | ||
| } | ||
|
|
||
| @Override | ||
| public String getMigrationType() { | ||
| return "TEST"; | ||
| } | ||
| } |
There was a problem hiding this comment.
Добавь контекста, что проверяется, в стиле Панкрашкина ничего не понять
There was a problem hiding this comment.
добавил комментов к тестам и названия тестов, тут суть что у нас есть способ в геке мигрировать трифт , но был баг что он брал промежуточный результат предыдущего шага всегда исходное и миграция по сути не работала и тесты проверяют работу BaseMigrationManager
| private ValueGenerator valueGenerator; | ||
|
|
||
| private Map<String, FieldHandler> fieldHandlers = new HashMap<>(); | ||
| private final Deque<Class<? extends TBase>> structPath = new ArrayDeque<>(); |
There was a problem hiding this comment.
поправил на сет , первоначально попал сюда как идея хранить путь рекурсии , но тк нам тут нужна только проверка встречался ли тип в текущей ветки или нет и этого хватит и через сет
|
|
||
| private void processStruct(StructMetaData structMetaData, StructHandler handler) throws IOException { | ||
| Class<? extends TBase> structClass = structMetaData.getStructClass(); | ||
| if (structPath.contains(structClass)) { |
There was a problem hiding this comment.
Правильно понимаю, что мы просто StackOv меняем на другое исключение, мб мы хотим просто пропустить ее и догенерить то что можем? Только ли это используется в тестах или может сломать и основные процессы?
There was a problem hiding this comment.
да, подробнее расписал в шапке ответа , затрагивает и TBaseProcessor.java и MockTBaseProcessor.java , то есть и основу
| ByteBuffer duplicate = ((ByteBuffer) value).duplicate(); | ||
| byte[] bytes = new byte[duplicate.remaining()]; | ||
| duplicate.get(bytes); | ||
| handler.value(bytes); |
There was a problem hiding this comment.
Какой то набор приведений, поясни что тут было сделано и зачем
There was a problem hiding this comment.
Какой то набор приведений, поясни что тут было сделано и зачем
Лучше не следовать стилю Панкрашкина, у него ничего не понятно он сишник
There was a problem hiding this comment.
поправил . цель корректно обработать ByteBuffer при сериализации
| } catch (InstantiationException | IllegalAccessException ex) { | ||
| throw new IOException(ex); | ||
| } finally { | ||
| structPath.pop(); |
There was a problem hiding this comment.
Точно ли нужно создавать Deque для того чтобы проверить что новый объект который тут же создается и тот который пришел будут одного типа, на сколько я понял логику? почему бы просто это и не проверить, для чего структура на уровне корня объекта с такой сложной логикой?
There was a problem hiding this comment.
да, не нужен , выше написал, нужна только проверка и ииспользуем сет . структура хранения не локальна потому что отлавливаем граф как A -> A так и A -> B -> A в данной ветке , нужен для всей ветки обхода, но обернут в ThreadLocal для изоляции и живет в контексте одного запуска process
|
|
||
| @Override | ||
| public boolean equals(Object other) { | ||
| return this == other; |
There was a problem hiding this comment.
ошибка, сделал RecursiveStruct
| return META_DATA_MAP; | ||
| } | ||
|
|
||
| public enum _Fields implements TFieldIdEnum { |
There was a problem hiding this comment.
почему тут еще и enum прям в тесте описан? Для чего он нужен
There was a problem hiding this comment.
вынес RecursiveStruct отдельно, TBase требует описание трифт полей, в код гене также
| } | ||
|
|
||
| public static _Fields findByThriftId(int fieldId) { | ||
| return fieldId == 1 ? NEXT : null; |
There was a problem hiding this comment.
маппинг в энам для fieldForId , это все имитация какого то интересного трифт объекта с рекурсией
| BinaryTest binaryTest = new BinaryTest(); | ||
| ByteBuffer buffer = ByteBuffer.wrap(new byte[]{9, 1, 2, 8}); | ||
| buffer.position(1); | ||
| buffer.limit(3); | ||
|
|
||
| binaryTest.setData(buffer); | ||
| binaryTest.setDataInList(Collections.emptyList()); | ||
| binaryTest.setDataInSet(Collections.emptySet()); | ||
| binaryTest.setDataInMap(Collections.emptyMap()); | ||
|
|
||
| BinaryCapturingHandler handler = new BinaryCapturingHandler(); | ||
| new TBaseProcessor().process(binaryTest, handler); |
There was a problem hiding this comment.
это тест по багу с ByteBuffer , смотрим что в сериализацию не попадает мусор
| ); | ||
| } | ||
|
|
||
| private static class BinaryCapturingHandler implements StructHandler<byte[]> { |
There was a problem hiding this comment.
еще какой-то страшный класс внутри теста, точно нужен тут?
Напоминает результат работы ИИ, в кратце что хотели сделать? |
karle0wne
left a comment
There was a problem hiding this comment.
... хотели ...
Да, без водкии в геке не разбраться.
в корневом описании хотел показать основные точки правок, но попробую еще раз сформулировать
TBaseProcessor.java MockTBaseProcessor.java могут уходить в бесконечную рекурсию и выдавать StackOverflowError и этот патч не решает корень этой проблемы (далее объясню) а делает явно перехват сигнатур похожих на рекурсию и выкидывает исключения , помимо этого по мелочам чистит баги, также тесты которые проверяют что эти кейсы закрылись
не может решить проблему в корне потому что сам гек имеет архитектурные ограничения (трифт джава ген это граф, json это дерево), чтоб это решить нужно вводить доп структуры где хранятся референсы на объекты которые проходили (как то подружить дерево и граф) , и судя по всему для этого нужно было бы сделать чуть ли не гек в2 , что не целесообразно. потому что там много форматов msdpack, xml, json и для каждого надо отдельно прорабатывать , поэтому остановились пока на такой небольшой доработки
то есть если резюмировать план работ
- перехват рекурсий
- баг с ByteBuffer когда нужен захват только активной части - он мог сериализовывать лишние байты (есть тест на эту ситуацию)
- баг когда не останавливалось выполенение в ObjectProcessor.java когда нашел set
- баг BaseMigrationManager.java что он не получал следующий шаг в миграции трифт схемы а всегда обращался к исходным данным
- тесты
- по мелочи
Стабилизируем
serializerиmigratorв тех местах, где библиотека вела себя непредсказуемо на сложных данных. Несколько исправлений: циклические thrift-структуры, рекурсивные схемы при генерации mock-объектов, передача данных через цепочку миграций и разбор некорректного входа в разных представлениях. Раньше такие случаи могли заканчиваться переполнением стека, бесконечным обходом структуры или просто неверной обработкой данных, поэтому задача этого патча именно в том, чтобы сделать поведение явным и безопасным.В
TBaseProcessorдобавлена проверка на зацикленные ссылки, вMockTBaseProcessorтакая же защита появилась для рекурсивных thrift-схем, вBaseMigrationManagerисправлена логика последовательной миграции, чтобы каждый следующий шаг получал уже преобразованный результат предыдущего шага. Заодно приведена в порядок обработка отдельных пограничных случаев вObjectProcessor,JsonProcessorиXMLProcessor: исправлено чтениеByteBuffer, убран ошибочный проход мимо веткиSET, и для неизвестных типов библиотека теперь сразу сообщает об ошибке понятным исключением.