Russian Qt Forum

Qt => Общие вопросы => Тема начата: GPPsoft от Декабрь 03, 2013, 05:37



Название: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 05:37
Здравствуйте. Переписываю один проект с java. В java я использую библиотеку gson для сериализации-десериализации. Как с этим в QT? По хорошему, хотелось бы чтобы это выглядело аналогично этому:
Псевдокод:
Код:
String<-toJson(myObj);
myObj<-fromJson(jsonString,Type);


Заранее огромное спасибо!

P.S: QT5


Название: Re: JSON сериализация-десериализация
Отправлено: xokc от Декабрь 03, 2013, 09:02
Собственно JSON парсер есть в Qt 5 "из коробки". Сериализацию/десериализацию объектов нужно будет допиливать самостоятельно.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 09:07
Собственно JSON парсер есть в Qt 5 "из коробки". Сериализацию/десериализацию объектов нужно будет допиливать самостоятельно.
Как это сделать? У QJsonDocument есть метод fromVariant... Могу ли я объект своего класса привести к QVariant?


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 09:12
Как это сделать? У QJsonDocument есть метод fromVariant... Могу ли я объект своего класса привести к QVariant?
Вначале нужно научить объекты своего класса (де)серилизоваться в QDataStream.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 09:17
Как это сделать? У QJsonDocument есть метод fromVariant... Могу ли я объект своего класса привести к QVariant?
Вначале нужно научить объекты своего класса (де)серилизоваться в QDataStream.
Как это сделать? Можно ссылку на туториал. Спасибо.


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 09:36
Как это сделать? Можно ссылку на туториал. Спасибо.
http://stackoverflow.com/questions/13835197/serializing-my-custom-class-in-qt


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 09:47
В этом блоге есть несколько статей по сериализации.
http://www.mimec.org/taxonomy/term/51


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 10:24
Ок. Написал класс из примера:
Код:
#ifndef PEOPLE_H
#define PEOPLE_H

#include <QObject>
#include <QDataStream>
#include <QMetaProperty>

class People : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int id READ getId WRITE setId)
    Q_PROPERTY(QString Name READ getName WRITE setName)

public:
    explicit People(QObject *parent = 0);
    int getId() const { return id; }
    void setId(int newId) { id = newId; }
    QString getName() const { return Name; }
    void setName(const QString &newName) { Name = newName; }

private:
    int id;
    QString Name;

signals:

public slots:

};

QDataStream &operator<<(QDataStream &ds, const People &obj);
QDataStream &operator>>(QDataStream &ds, People &obj) ;
#endif // PEOPLE_H

Код:
#include "people.h"

People::People(QObject *parent) :
    QObject(parent)
{
}


QDataStream &operator<<(QDataStream &ds, const People &obj) {
    for(int i=0; i<obj.metaObject()->propertyCount(); ++i) {
        if(obj.metaObject()->property(i).isStored(&obj)) {
            ds << obj.metaObject()->property(i).read(&obj);

        }
    }
    return ds;
}
QDataStream &operator>>(QDataStream &ds, People &obj) {
    QVariant var;
    for(int i=0; i<obj.metaObject()->propertyCount(); ++i) {
        if(obj.metaObject()->property(i).isStored(&obj)) {
            ds >> var;
            obj.metaObject()->property(i).write(&obj, var);
        }
    }
    return ds;
}

Как теперь привести его к QVariant?


Название: Re: JSON сериализация-десериализация
Отправлено: Johnik от Декабрь 03, 2013, 10:43
http://qt-project.org/doc/qt-4.8/qvariant.html
читаем раздел: Detailed Description


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 10:54
Как теперь привести его к QVariant?
Посмотрел доку на QJsonDocument. fromVariant создает объект JsonDocument из QVariantList/QVariantMap, который и должен лежать в указаном variant. Из пользовательского объекта json документ получить не получится.

Нужно будет сделать например функцию:
Код
C++ (Qt)
QJsonObject toJson( const MyClass &obj )
{
   QJsonObject res;
   // Сохраняем поля объекта в объекте JsonObject
   return res;
}
 


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 11:21
Как теперь привести его к QVariant?
Посмотрел доку на QJsonDocument. fromVariant создает объект JsonDocument из QVariantList/QVariantMap, который и должен лежать в указаном variant. Из пользовательского объекта json документ получить не получится.

Нужно будет сделать например функцию:
Код
C++ (Qt)
QJsonObject toJson( const MyClass &obj )
{
   QJsonObject res;
   // Сохраняем поля объекта в объекте JsonObject
   return res;
}
 

Спасибо. Но слишком много классов(около 30) у меня которые нужно портировать из Java. Не вариант. Если бы как-нибудь автоматизировать этот процесс. подхватывать открытые поля к примеру. Печально все короче...


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 11:28
Спасибо. Но слишком много классов(около 30) у меня которые нужно портировать из Java. Не вариант. Если бы как-нибудь автоматизировать этот процесс. подхватывать открытые поля к примеру. Печально все короче...
Так сделайте методы в базовом классе, которые будут сохранять/загружать все свойства, только не в QDataStream, а в QJsonObject.
Посмотрите на пример, который вы сами привели чуть выше. :)
Все можно решить двумя методами. ;)


Название: Re: JSON сериализация-десериализация
Отправлено: Johnik от Декабрь 03, 2013, 11:31
QJsonValue QJsonValue::fromVariant(const QVariant & variant) [static]

не может помочь?


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 11:56
не может помочь?
Он поможет при сохранении полей пользовательского класса в QJsonObject.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 12:01
не может помочь?
Он поможет при сохранении полей пользовательского класса в QJsonObject.
Вообщем сейчас попробую через свойства и потом в цикле заполнять QVariantMap значениями. Вот бы еще десереализацию как-нибудь придумать...


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 12:06
Вот бы еще десереализацию как-нибудь придумать...
Все это есть в примере выше, только вместо чтения из QDataStream, значение нужно будет брать из QVariantMap.


Название: Re: JSON сериализация-десериализация
Отправлено: Johnik от Декабрь 03, 2013, 12:23
Вот бы еще десереализацию как-нибудь придумать...

обратно сериализации...

например:
1. QVariant QJsonValue::toVariant() const
2. QVariant::toMap()
3. пробежаться по полям и заполнять setProperty() объекта


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:05
Вот бы еще десереализацию как-нибудь придумать...
Все это есть в примере выше, только вместо чтения из QDataStream, значение нужно будет брать из QVariantMap.
А как получить имя поля которое я должен поместить в QVariantMap?

Код:
QVariantMap MainWindow::toMap(QObject obj)
{
    QVariantMap map;
   
   for(int i=0; i<obj.metaObject()->propertyCount(); ++i) {
        if(obj.metaObject()->property(i).isStored(&obj)) {
          QVariant var = obj.metaObject()->property(i).read(&obj);---Тут QVariant
          map.insert(???,var);
        }
    }

    return map;
}

Код:
#ifndef GPPPACKET_H
#define GPPPACKET_H

#include <QObject>

class GPPPacket : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString head READ getHead WRITE setHead)

private:
    QString head;

public:
    explicit GPPPacket(QObject *parent = 0);
    void setHead(QString head){this->head=head;}
    QString getHead(){return head;}
signals:

public slots:

};

#endif // GPPPACKET_H


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 13:15
А как получить имя поля которое я должен поместить в QVariantMap?
obj.metaObject()->property(i).name()


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:18
А как получить имя поля которое я должен поместить в QVariantMap?
obj.metaObject()->property(i).name()
Ок. Нашел obj.metaObject()->property(i).name(). И как я сразу его не заметил.  Но теперь другая проблема откуда-то берется поле с названием objectName. Можно ли как то его опустить? Или придется 0 элемент просто игнорировать?


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 13:22
Ок. Нашел obj.metaObject()->property(i).name(). И как я сразу его не заметил.  Но теперь другая проблема откуда-то берется поле с названием objectName. Можно ли как то его опустить? Или придется 0 элемент просто игнорировать?
Проще проверять имя свойства и пропускать его, т.е. не записывать его в QVariantMap.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:30
Почему-то не подхватываются свойства потомков

Код:
#ifndef SCREENPREVIEW_H
#define SCREENPREVIEW_H

#include<gpppacket.h>

class ScreenPreview: public GPPPacket
{
    Q_PROPERTY(QString data READ getData)
    Q_PROPERTY(int index READ getIndex)

private:
    QString data;
    int index=-1;
public:
    ScreenPreview(int index,QString data);
    QString getData(){return data;}
    int getIndex(){return index;}
};

#endif // SCREENPREVIEW_H


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 13:45
Почему-то не подхватываются свойства потомков
Покажите, что в GPPPacket, как происходит сериализация.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:47
Почему-то не подхватываются свойства потомков
Покажите, что в GPPPacket, как происходит сериализация.

GPPPacket смотрите выше.
Сериализация:
Код:
QVariantMap MainWindow::toMap(QObject &obj)
{
    QVariantMap map;

    for(int i=0; i<obj.metaObject()->propertyCount(); ++i) {
        if(obj.metaObject()->property(i).isStored(&obj)) {
          map.insert(obj.metaObject()->property(i).name(),obj.metaObject()->property(i).read(&obj));
        }
    }

    return map;
}

имен свойств data и index нет.


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 13:52
Добавляйте к вашим свойствам [... STORED true]


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:54
Добавляйте к вашим свойствам [... STORED true]

Код:
Q_PROPERTY(QString data READ getData STORED true)
Q_PROPERTY(int index READ getIndex STORED true)

Без толку.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 13:58
Подхватывается только head из GPPPacket, ну и objectName


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 13:58
Без толку.
Покажите как используете, а лучше выложите архив с компилябельным примером.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 14:09
Без толку.
Покажите как используете, а лучше выложите архив с компилябельным примером.

Класс GPPPacket:
Цитировать
#ifndef GPPPACKET_H
#define GPPPACKET_H

#include <QObject>

class GPPPacket : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString head READ getHead WRITE setHead)

private:
    QString head;

public:
    explicit GPPPacket(QObject *parent = 0);
    void setHead(QString head){this->head=head;}
    QString getHead(){return head;}
signals:

public slots:

};

#endif // GPPPACKET_H

Класс потомок от GPPPacket:
Код:
#ifndef SCREENPREVIEW_H
#define SCREENPREVIEW_H

#include<gpppacket.h>

class ScreenPreview: public GPPPacket
{
    Q_PROPERTY(QString data READ getData)
    Q_PROPERTY(int index READ getIndex)

private:
    QString data;
    int index=0;
public:
    ScreenPreview();
    QString getData(){return data;}
    int getIndex(){return index;}
};

#endif // SCREENPREVIEW_H

Сериализация в QVariantMap:
Код:
QVariantMap MainWindow::toMap(QObject &obj)
{
    QVariantMap map;

    for(int i=0; i<obj.metaObject()->propertyCount(); ++i) {
        if(obj.metaObject()->property(i).isStored(&obj)) {
          map.insert(obj.metaObject()->property(i).name(),obj.metaObject()->property(i).read(&obj));
        }
    }

    return map;
}

Инициализация и использование:
Код:
ScreenPreview preview;
QMessageBox::information(this,"Информация",QJsonDocument::fromVariant(toMap(preview)).toJson());

Вывод:
Код:
{
   "head":"",
   "objectName":""
}


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 14:13
Могу только гадать.
Не увидел [STORED true], ну наверное они есть. :)
Попробуйте, закомментировать проверку isStored.


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 14:15
Могу только гадать.
Не увидел [STORED true], ну наверное они есть. :)
Попробуйте, закомментировать проверку isStored.
Никакой разницы. Выложить исходники?


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 14:17
Выложить исходники?
Не надо. Вы забыли Q_OBJECT в ScreenPreview.



Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 14:24
Выложить исходники?
Не надо. Вы забыли Q_OBJECT в ScreenPreview.
Надо :). Добавил Q_OBJECT - результата нет.


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 14:25
Надо :). Добавил Q_OBJECT - результата нет.
Не надою :)
Запустите qmake еще раз.


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 14:29
Должно быть так:
Код
C++ (Qt)
#ifndef SCREENPREVIEW_H
#define SCREENPREVIEW_H
 
#include<gpppacket.h>
 
class ScreenPreview: public GPPPacket
{
   Q_OBJECT
   Q_PROPERTY(QString data READ getData)
   Q_PROPERTY(int index READ getIndex)
 
private:
   QString data;
   int index=0;
public:
   ScreenPreview();
   QString getData(){return data;}
   int getIndex(){return index;}
};
 
#endif // SCREENPREVIEW_H
 
Это обязательно для moc.

И после добавления Q_OBJECT нужно выполнить qmake.
У меня все работает. :)


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 14:34
Должно быть так:
Код
C++ (Qt)
#ifndef SCREENPREVIEW_H
#define SCREENPREVIEW_H
 
#include<gpppacket.h>
 
class ScreenPreview: public GPPPacket
{
   Q_OBJECT
   Q_PROPERTY(QString data READ getData)
   Q_PROPERTY(int index READ getIndex)
 
private:
   QString data;
   int index=0;
public:
   ScreenPreview();
   QString getData(){return data;}
   int getIndex(){return index;}
};
 
#endif // SCREENPREVIEW_H
 
Это обязательно для moc.

И после добавления Q_OBJECT нужно выполнить qmake.
У меня все работает. :)

Спасибо, все работает! Вы меня извините, но я всю жизнь программировал на .NET,Java и с С++ и QT знаком поверхностно. Что такое moc и как qmake выполнить через QT Creator? Я пока просто удалил папку с скомпилиными объектами и все заработало. Еще раз спасибо. Думаю я еще не одну ветку с вопросами тут задам. Проект надо переносить на QT.


Название: Re: JSON сериализация-десериализация
Отправлено: Old от Декабрь 03, 2013, 14:42
Что такое moc и как qmake выполнить через QT Creator?
moc это Qtешный Meta object compilator, работает перед плюсовым и генерирует некоторые дополнительные файлы. Нужен для обеспечения всех метообъектный кайфов.

По второму вопросу: Сборка > Запустить qmake.
Как правило все происходит автоматически, но в таких случаях, когда сразу забыл указать Q_OBJECT его приходиться запускать руками.


Название: Re: JSON сериализация-десериализация
Отправлено: gil9red от Декабрь 03, 2013, 14:51
Цитировать
Что такое moc
Это мета-объектный компилятор :)
Он обрабатывает расширения C++ от Qt :)
Благодаря нему, например, реализуется система слотов-сигналов :)

Цитировать
как qmake выполнить через QT Creator?
В левой части креатора есть дерево проектов :)
тыкните правой кнопкой на шапку вашего проекта и выберите нужное действие :)

PS. QT - QuickTime, а Qt - это Qt ;D

UPDATE. не заметил, что уже ответили :)


Название: Re: JSON сериализация-десериализация
Отправлено: GPPsoft от Декабрь 03, 2013, 14:57
Спасибо ребят! На сегодня мне хватит Qt. Пойду спать :)