Просмотр полной версии : Flex4, RemoteObject, ArrayCollection ошибка десериализации.
Всем доброго дня.
Я тут наткнулся на одну очень неприятную фишку при передачи данных со стороны сервера (Java) на клиент (Flex 4).
На стороне клиента есть два класса со следующей сигнаторуй
public class A {
public String prostoSvoystvo;
public List<B> moyMassiv;
}
public class B {
public String drugoeProstoeSvoystvo;
}
На стороне клиента так же есть два класса
[RemoteClass(alias="A")]
public class A {
public var prostoSvoystvo : String;
public var moyMassiv : ArrayCollection;
}
[RemoteClass(alias="A")]
public class B {
public var drugoeProstoeSvoystvo : String;
}
Так вот, когда делаю вызов, то происходит следующее: класс А десериализуется нормально, а вот в свойство moyMassiv попадает коллекция не объектов типа B, а просто коллекция объектов Object с нужными полями. :wacko:
Кто-нибудь сталкивался с таким странным поведением? Может есть варианты лечения?
На стороне сервера используется BlazeDS, но есть подозрения, что проблема на стороне флекса. Sdk Flex = 4.1.0.15646
Dimitry_II
18.06.2010, 12:13
У меня практически такая же загвоздка, только с точностью до наоборот - все зависимые объекты и коллекции сериализовались, а "главная" коллекция объектов пришла как ArrayCollection объектов типа Object. Правда, банальное item[i] as B легко их переводит. Но недоразумение осталось. Да и во флешевских логах хватает строк типа:
warning: unable to bind to property 'label' on class 'Object' (class is not an IEventDispatcher)
Тоже с большим удовольствием узнал бы решение.
Gubber: с явовской сериализацией не работал, но с другой стороны - а почему вы решили, что ArrayCollection должна сериализоваться в List<T>? Как бы нет к тому никаких явных предпосылок. ArrayCollection - просто какой-то левый класс из флексового фреймворка, и если уже на что-то в яве похожа, так скорее на ArrayList (без параметра типа, как в jdk <1.5) и то очень отдаленно, т.как это по-настоящему не коллекция, разработчики просто забыли "view" к имени класса дописать, - такой себе мутант / суррогат чего-то непонятного.
На стороне AS3 ArrayCollection сериализуется так же, как и массив, только с той разницей, что дописывается алиас на класс. По аналогии с PHP могу предположить, что в яве, в AMF пакете должен быть какой-нибудь класс, который ей соответствует, или нужно самому такой дописывать.
Dimitry_II: В AS3 нет существует конвертирования типов для не-ECMAScript классов, т.е. если as сработало, значит объекты и были нужного типа. Это значит, что только типы вроде int, String и т.п можно конвертировать друг в друга, сложные типы таким образом не конвертируются.
Gubber: с явовской сериализацией не работал, но с другой стороны - а почему вы решили, что ArrayCollection должна сериализоваться в List<T>? Как бы нет к тому никаких явных предпосылок. ArrayCollection - просто какой-то левый класс из флексового фреймворка, и если уже на что-то в яве похожа, так скорее на ArrayList (без параметра типа, как в jdk <1.5) и то очень отдаленно, т.как это по-настоящему не коллекция, разработчики просто забыли "view" к имени класса дописать, - такой себе мутант / суррогат чего-то непонятного.
List - это интерфейс, одной из реализацией которого является ArrayList. При сериализации любого List на флексе он преобразуется в ArrayCollection.
Но вопрос не в этом, а втом, что не десериализуются внутренности этой коллекции - сама коллекция нормально десериализуется. Т.е. я получаю ArrayCollection, внутри которого набор объектов типа Object, а хотелось бы, чтобы это была коллекция объектов типа В.
Одельно объекты типа В нормально десериализуются.
P.S. при компиляции Generic'и<T> удбираются из кода.
Ну тогда вам не повезло с AMF библиотекой :) т.как ArrayCollection - просто бесполезная чушь. Но смысл не в этом, а в том, что это значит, что либо алиас не зарегистрирован, либо как-то не правильно зарегистрирован. Проще всего проверить, зарегистрирован ли на стороне флеша - записать и прочитать из ByteArray, если прочитался как нужный класс, а не как динамический объект, тогда на стороне флеша все ОК - как проверить в (по всей видимости BlazeDS?) - чесно не знаю.
По поводу путаницы с интерфейсами - сорри, я не ахти знаю явовские коллекции, но имелось в виду, что ArrayCollection - это просто пользовательский класс, примечательный только исключительным уродством задумки и отсутствием всякого смысла / назначения. Как бы нет в нем ничего общего с коллекциями кроме случайной созвучности в названии.
Ну тогда вам не повезло с AMF библиотекой :) т.как ArrayCollection - просто бесполезная чушь. Но смысл не в этом, а в том, что это значит, что либо алиас не зарегистрирован, либо как-то не правильно зарегистрирован.
Зарегистрировано всё правильно, т.к. по отдельности классы десериализуются нормально, а внутри коллекции, которая является свойтсвом другого объекта - не хочет.
Показывайте код тогда. Т.как так как вы говорите в принципе быть не может. Все, что делает ArrayCollection когда сериализуется выглядит так:
output.writeObject(this.source); Т.е. она просто массив объектов записывает.
Dimitry_II
19.06.2010, 02:37
Ну да, это может показать и дебаггер, что ArrayCollection - это фактически массив в обертке. Правда, я не очень понял предвзятости к этому объекту, так как а) именно его выбрали для сериализации практически любого (!) списочного объекта Java (а их там ой как много!) и б) он реализует с помощью курсоров автоматическую сортировку, что немаловажно. Правда, слегонца бесит невозможность получить индекс объекта простой функцией, приходится перебирать ... это есть неправильно.
А что касается сериализации, то в получаемой коллекции объектов наблюдается порядочная вложенность (сервер извлекает данные в одну структуру из 2 десятков таблиц) и везде (!), где есть набор (коллекция ArrayCollection), там находится коллекция именно нужных типов объектов (на клиенте зеркальная структура POJO/BOJO(?) объектов), кроме "главной" коллекции.
Кстати, на сайте оффдоки есть таблицы сериализации/десериализации между Flex и Java (BlazeDS/LCDS) и все сделано в точности с ней, хотя и сложно ошибиться. А "не-ECMAScript" классы великолепно сериализуются, если на клиенте есть AS-класс с [RemoteClass(alias="myproject.myclass")]. Хотя большого опыта нет, но работает все как часики.
Еще пару слов о сериализации/десериализации с сервера на клиент: как-то писал, но решения не нашел, пришлось обходить. На Java есть тип boolean и класс Boolean. Первый имеет только 2 возможных значения: true и false, класс же может иметь и null-значение. У AS есть класс Boolean, в которое сериализируется и boolean, и Boolean (согласно таблицам в оффдоке). Но реально если на сервере было свойство объекта типа Boolean со значением null, то на клиенте мы все равно получим false, как будто передаем boolean, а не Boolean.
ОК, почему предвзятость:
ArrayCollection называется не правильно, это представление коллекции. Это не коллекция. Он не работает с векторами. Он очень медленный. Но самое плохое, что в нем есть это механизм IPE - ItemPendingError этот механизм якобы обеспечивает пейджинг. Т.е. гипотетически можно переслать только часть данных / заполнить коллекцию частично, но оперировать ею так, как будто она заполнена целиком. Этот механизм написан очень плохо, и от него только проблем больше. Например, с какого-то перепуга ArrayCollection считает себя в праве самостоятельно заменять элементы в массиве, который обороачивает или просто дублировать массив. Представьте на секунду, что у вас в массиве находятся ссылки на файлы, а тут какой-то, не побоюсь этого слова, идиот, взял и сдублировал этот массив - попытался создать копию файлов... Кроме того, в ситуациях, когда эта дрянь работает с Object'ами или Proxy, оно создает им дополнительное свойство по которому оно их распознает, типа uid / mx_internal_uid а потом пытается исходя из этого заменять объекты, что неминуемо приводит к ошибка / ситуации когда не возможно понять с каким именно объектом вы работаете и т.п. Вообще, можно долго этот класс ругать, вам это не поможет, т.как Адоби писали фреймворк который вы используете, и просто хотели пропихнуть свою ахинею / сделать так, чтобы вам пришлось использовать их AS3 фреймворк...
В конце концов, если хочется использовать флексовые представления коллекций, то есть смысл использовать их интерфейсы, а имплементации писать самому, ну и лучше использовать IList, а не ICollectionView, у последнего еще и багов немеряно. Смысл будет в том, что после танцов с бубном это можно будет прикрутить к флексовым GUI компонентам. Не то, чтобы эти компоненты были чем-то лучше остальной части фреймворка, но это просто много работы их с нуля писать.
Вы не поняли про не-ECMAScript классы. Речь была о том, что можно коневерировать var i:int = int("1"); но нельзя var m:MovieClip = MovieClip(new BitmapData()); например.
Про Boolean в яве - знаете анекдот про програмиста и два стакана? Когда програмист ложится спать, то ставит рядом с кроватью два стакана - один с водой, другой пустой, первый - на случай если проснется ночью и захочется пить, а вротой на случай если не захочется. К сожалению флексовый фреймоврк написан ява програмистами, и я бы не удивился, если бы в нем была бы возможность как-то протащить этот бред из явы и похожее ООП спинного мозга, но, ради бога, зачем вам этот бред?
Dimitry_II
20.06.2010, 01:39
Ну, за ArrayCollection ничего говорить не буду - просто склоняю шляпу перед опытом, пока сам его не набрал.
Хотя для того использования, где он применяется для сериализации, не вижу (по крайней мере пока) его "неполноценности". Возможно, это отношение со временем изменится.
Про Boolean ты не прав: если мы говорим про int, long или boolean, мы говорим не про Объект, а про тип данных и было бы глупо, чтобы они были равны null или не были равны "ничему". Однако типы-классы Integer, Long, Boolean обязаны это поддерживать, так как они объекты; и это находит отличное подтверждение для связи БД - когда поля просто не имеют значений вне зависимости от типа. И хотя то же булевское свойство вроде как должно иметь только значение "правда" и "ложь", но на самом деле имеет еще значение "не указано" или "не введено" или "неизвестно". И эту функциональность я хочу иметь и при сериализации. Спрашивается, почему я обязан переходить на Integer с состояниями 0, 1 и null только из-за этой "недоработки"?
Думаю, насчет Java и его ООП спор совершенно бессмысленный, так как а) ты в этом вопросе явно предвзятый; и б) ты сильно ошибаешься - это задумывали фактически как самый совершенный язык и он пока таким и остается ... по крайней мере в этом вопросе. (извини, если несколько твоих выпадов я принял именно за недовольство этим Языком)
Бритва Оккама - знакомо? Вот, ArrayCollection это и есть лишная сущность. Т.е. Array сериализуется безо всяких дополнительных усилий. А ArrayCollection - непонятно зачем, но тоже сериализуется в то же самое.
По поводу Boolean - я прав :p Никому кроме Java програмистов не нужен Boolean у которого есть 3 возможных значения. Если нужно три разных значения - есть энумераторы, вот их и используйте, а логические величины не могут и не должны быть nullable. То, что в AS3 Boolean ведет себя как положено - не "недоработка", это в Яве от большого ума и стремления сделать все одинаково не задумываясь о последсвиях. Проблема в Яве, как и в похожих языках в том, что из функции надо возвращать одно значение, и нельзя вернуть несколько разных. В C# решается проще и красивше - можно в функцию передать параметр по ссылке (ref / out). А в Яве либо бросать искючение (затратно), либо вот такой вот маразм с Integer, Boolean и т.п. Есть и другие варианты решения, например в HaXe можно описать такую ситуацию как function foo():Null<Int> и она будет возвращать либо null либо число. Ява старый язык, который давно уже не развивается, попытки с ним что-то то сделать выглядят просто неуклюже, да и не интересно это уже никому... Какое-то время Ява была "образцом ООП", но времена поменялись, ООП в таком виде, как он в Яве уже никому не интересен т.как обнаружилось много недостатков, которые уже никак не исправить - вот Boolean - один из них.
Но я больше не буду про Яву, - я действительно ее не перевариваю.
Dimitry_II
20.06.2010, 16:53
Да, не надо про Java ... твои доводы не являются таковыми.
А "нюанс" с Boolean как раз очень красиво выглядит, так как сохраняется принцип "все есть объект", а следовательно, любой объект может быть null.
Кстати, почему-то считал, что во флеше Boolean такой же ... если бы проверил сразу, то не возникло бы вопросов. Оказывается - только 2 состояния (null приравнивается к false).
квантовая логика)
Cостояние Boolean в AS3 может быть null только до тех пор пока не существует Наблюдателя. Как только мы хотим узнать значение - оно превращается в false/true))
А еще бывает отрицательный ноль, например, тоже "удобно" но так же бессмысленно.
http://govnokod.ru/3274 - хоть и сишарп, но тенденция от туда же.
Про Boolean
Ой как не прав. Зачем мне приводить ответ пользователя "Вы мальчик" к числовому значению, только потому что он может сказать "Я не определился" :D. К тому же не забывай в БД любое поле может иметь пустое значение в том числе и тип Boolean. И от этого зависит поведение системы: мальчикам - про машины и девочек; девочкам - про косметику и мальчиков, а неопределившимся - про хороших хирургов:wacko:.
И потом вы уже ушли в другую тему.
Т.е. как я понял ни кто не сталкивался с похожей сложностью и не нашёл для неё решения.
Dimitry_II
22.06.2010, 19:53
У всех своя правда ... с точки зрения Java нам это кажется действительно удобным и правильным (и я сторонник этого и приводил эти же доводы). Но уважамый модератор изначально неприемлит Java, поэтому любые споры в этом направлении так или иначе приведут к позиции "дурак - сам дурак".
А что касается "сложности" ... если ручное приведение типов не вызывает ошибки, то либо а) точно проверить все поля и их видимость или б) при получении приводить вручную.
Кстати, а можно посмотреть твои POJO-флеш-классы?
> К тому же не забывай в БД любое
Вы теперь и базы данных на Яве пишете? В SQL как бы всю жизнь была возможность задать полю not null, что аналогично not nullable во всех остальных языках. Если у вас есть 3 варианта - используйте энумератор, булиан он для других вещей предназначен (в том же MySQL замечательно поддерживается).
Просто, поймите, что Ява уникален в том, как он относится к Boolean, никто в других языках не хочет такой функционал, и поэтому на претензии типа "а почему это так не работает в AS3" можно только ответить, что в AS3 это работает правильно, а в Яве - нет.
Dimitry_II
24.06.2010, 14:09
Те, кто попробовал и оценил (ну, тот же булеан в 3 состояниях), уже не совсем понимают отказ "других" от этого удобства. Претензий нет :), есть "другой" взгляд ...
Да, и поэтому, те, кто оценил прелести Явы пишут на Скала, например ;) Как же так получилось, что люди, которые очень любили этот замечательный язык, решили в первую очередь выбросить nullable booleans из своего арсенала?
Dimitry_II
24.06.2010, 23:17
Ну и зачем, спрашивается, переходить в банальную полемику?
Люди переходят не только с Джавы на Скалу, но еще и на множество других ФУНКЦИОНАЛЬНЫХ языков, которые и созданы специально для того, чтобы быстро и эффективно сделать приложение. Ведь подавляющему большинству не нужна вся потрясающая гибкость языка, нужна эффективность его использования.
"Пукать в воздух" при спорах - этого я не люблю. "... решили в первую очередь ...", "... которые очень любили ...", "... выбросить ... из своего арсенала ..." - не слишком пафосно для такой банальной вещи? - При чем тут Boolean, который и виноват всего лишь в том, что наследует (по всем правилам и требованиям языка) предка - Object, то есть может быть null?
Что касается Scala и его булевского класса ...
В Java есть класс Integer и литерал int, класс Long и литерал long, класс Boolean ... без литерала ... ну вот посчитали, что литерал не нужен.
В Scala решили наоборот - сделать литерал. Из оффдоки:
abstract final class Boolean extends AnyVal
AnyVal has a fixed number subclasses, which describe values which are not implemented as objects in the underlying host system.
"... which are not implemented as objects ..." - они просто примитивизировали класс.
Но! Насколько я понимаю, никто не запрещает использовать java.lang.Boolean? Или ошибаюсь?
alexberkut
25.06.2010, 14:07
много букаф... проблему решили?
судя по коду
[RemoteClass(alias="A")]
public class A {
public var prostoSvoystvo : String;
public var moyMassiv : ArrayCollection;
}
[RemoteClass(alias="A")]
public class B {
public var drugoeProstoeSvoystvo : String;
}
на ремоут класс А пытаються замапиться два класса на флексе А и В.
Проблема может быть ещё и в том, как флекс десериализует объекты.
Если вы используете мета тэг [RemoteClass] то флекс подхватит это только тогда когда класс впервые будет использован (и то не всегда). Те если класс В никто не пользовал то и когда с сервера прилетят данные флекс не поймёт куда их десериализовать.
Два решения:
1. галимое:
[RemoteClass(alias="A")]
public class A {
B; //тупо юзаем класс, чтобы флекс зарегистрировал его
public var prostoSvoystvo : String;
public var moyMassiv : ArrayCollection;
}
[RemoteClass(alias="A")]
public class B {
public var drugoeProstoeSvoystvo : String;
}
но тоже работает не на 100% случаев (в более сложных, модульных апликейшенах может не работать)
2. работает всегда
использовать registerClassAlias ("<java class>", <flex class>);
к примеру
registerClassAlias ("A", A);
писать это при ините апликейшена до первых ремоут колов к яве.
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.