3

I'm using Qt and trying to take the following and convert it into JSON text, but when I attempt to compile it I get a symbols not found for architecture error.

I'm currently using the builtin Qt Json library as I do not know how to get QJson to work and compile statically into the code so that there are no dependencies.

// Create the message body QVariantMap message; message.insert("date", QDate::currentDate().toString()); message.insert("eventType", eventName); message.insert("payload", messagePayload); // Initialize the Serializer QJson::Serializer serializer; bool ok; // Serialize the data QByteArray json = serializer.serialize(message, &ok); 

The compiler output is the following:

Undefined symbols for architecture x86_64: "QJson::Serializer::serialize(QVariant const&, bool*)", referenced from: SWebsocketClient::sendMessage(QString, QMap<QString, QVariant>) in swebsocketclient.o 

Is this kindof the right way to do this, or is there a much better? I know this question has been asked elsewhere, however most of the articles linked to in other answers do not exist anymore.

6
  • Offhand it looks like the QJson library isn't built for that architecture. Commented Jan 21, 2013 at 20:51
  • How did you obtain/build Qjson? How do you link it? Show your .pro file. Commented Jan 21, 2013 at 21:31
  • @FrankOsterfeld I did nothing to build/obtain QJson. I tried installing it via homebrew on my mac and then adding "QT += sql qjson" to my .pro file, but I thought Qt had some JSON support builtin? If not, how is it that I use QJson in my project if I install it view homebrew? Commented Jan 22, 2013 at 0:25
  • 1
    If it was built-in, one wouldn't need qjson (Json support is part of Qt5, not part of Qt4 though). For CONFIG += qjson (CONFIG, not QT) to work, qjson would need to install a .prf file, which I don't see in the repo. (It's using CMake which makes these things a lot easier). So I assume you need to do LIBS += -lqjson manually Commented Jan 22, 2013 at 7:41
  • @FrankOsterfeld That worked! Thanks! I don't know if you want to post that as an answer or if I should go ahead and answer my own question. But I think you should take the credit. Commented Jan 22, 2013 at 18:21

1 Answer 1

2

You can always use this JSON library instead:

/* * qvjson.h * * Created on: Apr 23, 2010 * Author: drh */ #ifndef QVJSON_H_ #define QVJSON_H_ #include <QMap> #include <QList> #include <QVariant> #include <QRegExp> class QvJson { public: QvJson(); virtual ~QvJson(); QVariant parseJson(const QString& jsonString); // The jsonObject is a QVariant that may be a -- // -- QMap<QString, QVariant> // -- QList<QVariant> // -- QString // -- integer // -- real number // -- bool // -- null (implemented as a QVariant() object) // Where QVariant appears in the above list, it may recursively // be one of the above. QString encodeJson(const QVariant& jsonObject); private: enum Error { ErrorUnrecognizedToken, ErrorMustBeString, ErrorMissingColon, ErrorMissingCommaOrClose, ErrorNoClosingQuote, ErrorEndOfInput, ErrorInvalidNumericValue, ErrorInvalidHexValue, ErrorUnrecognizedObject }; QRegExp mNonBlank; QRegExp mFindQuote; QString nextToken(const QString& jsonString, int& position); QString peekToken(const QString& jsonString, int position); QVariant parseInternal(const QString& jsonString, int& position, int nesting); QVariant parseObject(const QString& jsonString, int& position, int nesting); QVariant parseArray(const QString& jsonString, int& position, int nesting); QVariant parseString(const QString& jsonString, int& position, int nesting); QVariant parseBool(const QString& jsonString, int& position, int nesting); QVariant parseNull(const QString& jsonString, int& position, int nesting); QVariant parseNumber(const QString& jsonString, int& position, int nesting); QVariant syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error); QString encodeObject(const QVariant& jsonObject); QString encodeArray(const QVariant& jsonObject); QString encodeString(const QVariant& jsonObject); QString encodeString(const QString& value); QString encodeNumeric(const QVariant& jsonObject); QString encodeBool(const QVariant& jsonObject); QString encodeNull(const QVariant& jsonObject); QString encodingError(const QString& method, const QVariant& jsonObject, Error error); }; #endif /* QVJSON_H_ */ /* * qvjson.cpp * * Created on: Apr 23, 2010 * Author: drh */ #include "qvjson.h" #include <QStringList> #include <QMessageBox> QvJson::QvJson() { mNonBlank = QRegExp("\\S", Qt::CaseSensitive, QRegExp::RegExp); mFindQuote = QRegExp("[^\\\\]\"", Qt::CaseSensitive, QRegExp::RegExp); } QvJson::~QvJson() { // TODO Auto-generated destructor stub } QVariant QvJson::parseJson(const QString& jsonString) { int position = 0; QVariant result; result = parseInternal(jsonString, position, 0); if (result.type() == QVariant::StringList) { QMessageBox::critical(NULL, "", result.toString()); } QString token(nextToken(jsonString, position)); if (!token.isEmpty()) { QMessageBox::critical(NULL, "", QObject::tr("Invalid JSON string -- remaining token %1 at position %2.").arg(token).arg(position)); } return result; } QString QvJson::nextToken(const QString& jsonString, int& position) { if (position >= jsonString.count()) { return QString(); } while (jsonString.at(position) == ' ') { position++; if (position >= jsonString.count()) { return QString(); } } if (jsonString.at(position).isLetter()) { if (position + 4 < jsonString.count()) { QString word = jsonString.mid(position, 4); if ((word == "true") || (word == "null")) { position += 4; while (position < jsonString.count() && jsonString.at(position) == ' ') { position++; } return word; } if ((word == "fals") && (position + 5 < jsonString.count()) && jsonString.at(position + 4) == 'e') { position += 5; while (position < jsonString.count() && jsonString.at(position) == ' ') { position++; } return "false"; } } } QString result = QString(jsonString.at(position)); position++; while (position < jsonString.count() && jsonString.at(position) == ' ') { position++; } return result; } // By virtue of its non-& position parm, this method "peeks" at the token without consuming it. QString QvJson::peekToken(const QString& jsonString, int position) { return (nextToken(jsonString, position)); } QVariant QvJson::parseInternal(const QString& jsonString, int& position, int nesting) { QString token(peekToken(jsonString, position)); QVariant result; int startPosition = position; // For debug Q_UNUSED(startPosition); if (token.isNull()) { result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorEndOfInput); } else if (token == "{") { result = parseObject(jsonString, position, nesting + 1); } else if (token == "[") { result = parseArray(jsonString, position, nesting + 1); } else if (token == "\"") { result = parseString(jsonString, position, nesting + 1); } else if ((token == "true") || (token == "false")) { result = parseBool(jsonString, position, nesting + 1); } else if (token == "null") { result = parseNull(jsonString, position, nesting + 1); } else if ((token == "-") || (token.at(0).isDigit())) { result = parseNumber(jsonString, position, nesting + 1); } else { result = syntaxError("parseInternal", jsonString, position, nesting + 1, ErrorUnrecognizedToken); } return result; } QVariant QvJson::parseObject(const QString& jsonString, int& position, int nesting) { QMap<QString, QVariant> resultObject; QString token; int startPosition = position; // For debug Q_UNUSED(startPosition); token = nextToken(jsonString, position); Q_ASSERT(token == "{"); // Handle case of empty object token = peekToken(jsonString, position); if (token == '}') { return QVariant(resultObject); } do { // Next item must be a string token = peekToken(jsonString, position); if (token != "\"") { return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMustBeString); } QVariant propName; propName = parseString(jsonString, position, nesting + 1); // Check for error if (propName.type() == QVariant::StringList) { QStringList propNameError(propName.toStringList()); propNameError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting); return QVariant(propNameError); } // Expect a ":" token = nextToken(jsonString, position); if (token != ":") { return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingColon); } // Now get the value QVariant propValue; propValue = parseInternal(jsonString, position, nesting + 1); // Check for error if (propValue.type() == QVariant::StringList) { QStringList propValueError(propValue.toStringList()); propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting); return QVariant(propValueError); } resultObject[propName.toString()] = propValue; // Next token must be a "," or "}" token = nextToken(jsonString, position); if (token == "}") { return QVariant(resultObject); } else if (token != ",") { return syntaxError("parseObject", jsonString, position, nesting + 1, ErrorMissingCommaOrClose); } } while (true); } QVariant QvJson::parseArray(const QString& jsonString, int& position, int nesting) { QList<QVariant> resultArray; QString token; token = nextToken(jsonString, position); Q_ASSERT(token == "["); // Handle case of empty object token = peekToken(jsonString, position); if (token == ']') { return QVariant(resultArray); } do { // Get the element of the array QVariant propValue; propValue = parseInternal(jsonString, position, nesting + 1); // Check for error if (propValue.type() == QVariant::StringList) { QStringList propValueError(propValue.toStringList()); propValueError << QObject::tr("in parseObject(%1,%2)").arg(position).arg(nesting); return QVariant(propValueError); } resultArray << propValue; // Next token must be a "," or "]" token = nextToken(jsonString, position); if (token == "]") { return QVariant(resultArray); } else if (token != ",") { return syntaxError("parseArray", jsonString, position, nesting + 1, ErrorMissingCommaOrClose); } } while (true); } QVariant QvJson::parseString(const QString& jsonString, int& position, int nesting) { QString result; // Skip over the double quote character Q_ASSERT(jsonString.at(position) == '"'); position++; do { if (position >= jsonString.count()) { return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote); } if (jsonString.at(position) == '"') { break; } if (jsonString.at(position) == '\\') { position++; if (position >= jsonString.count()) { return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote); } switch (jsonString.at(position).unicode()) { case 'b': result.append('\b'); break; case 'f': result.append('\f'); break; case 'n': result.append('\n'); break; case 'r': result.append('\r'); break; case 't': result.append('\t'); break; case 'u': { if (position + 4 >= jsonString.count()) { return syntaxError("parseString", jsonString, position, nesting, ErrorNoClosingQuote); } QString hex = jsonString.mid(position + 1, 4); bool ok; int value = hex.toInt(&ok, 16); if (!ok) { return syntaxError("parseString", jsonString, position+1, nesting, ErrorInvalidHexValue); } result.append(QChar(value)); position += 4; } default: result.append(jsonString.at(position)); } position++; } else { result.append(jsonString.at(position)); position++; } } while(true); Q_ASSERT(jsonString.at(position) == '"'); position++; return QVariant(result); } QVariant QvJson::parseBool(const QString& jsonString, int& position, int nesting) { bool resultBool; QString token; token = nextToken(jsonString, position); if (token == "true") { resultBool = true; } else if (token == "false") { resultBool = false; } else { Q_ASSERT(false); } return QVariant(resultBool); } QVariant QvJson::parseNull(const QString& jsonString, int& position, int nesting) { QString token; token = nextToken(jsonString, position); Q_ASSERT(token == "null"); Q_UNUSED(token); return QVariant(); } QVariant QvJson::parseNumber(const QString& jsonString, int& position, int nesting) { int startPosition = position; // Allow a leading minus sign if (jsonString.at(position) == '-') position++; if (position >= jsonString.count()) { return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorEndOfInput); } // Allow one or more decimal digits if (!jsonString.at(position).isDigit()) { return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue); } while (position < jsonString.count() && jsonString.at(position).isDigit()) { position++; } if (position >= jsonString.count() || (jsonString.at(position) != '.' && jsonString.at(position) != 'e' && jsonString.at(position) != 'E')) { bool ok = false; int resultInt = jsonString.mid(startPosition, position - startPosition).toInt(&ok); if (!ok) { return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue); } return QVariant(resultInt); } // Consume any fraction part if (jsonString.at(position) == '.') { position++; while (position < jsonString.count() && jsonString.at(position).isDigit()) { position++; } } // Consume any exponent part if (jsonString.at(position) == 'e' || jsonString.at(position) == 'E') { position++; // Consume +/- if present if (jsonString.at(position) == '+' || jsonString.at(position) == '-') { position++; } // Must have at least one digit if (!jsonString.at(position).isDigit()) { return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue); } while (position < jsonString.count() && jsonString.at(position).isDigit()) { position++; } } // Should have a valid floating point value at this point bool ok = false; qreal resultReal = jsonString.mid(startPosition, position - startPosition).toDouble(&ok); if (!ok) { return syntaxError("parseNumber", jsonString, position, nesting + 1, ErrorInvalidNumericValue); } return QVariant(resultReal); } QVariant QvJson::syntaxError(const QString& method, const QString& jsonString, int position, int nesting, Error error) { QString text; switch (error) { case ErrorInvalidNumericValue: text = QObject::tr("Invalid numeric value"); break; case ErrorInvalidHexValue: text = QObject::tr("Invalid hex value"); break; case ErrorEndOfInput: text = QObject::tr("Unexpected end of input"); break; case ErrorNoClosingQuote: text = QObject::tr("No closing quote for literal string"); break; case ErrorMissingColon: text = QObject::tr("Missing ':' between attribute name and value"); break; case ErrorMissingCommaOrClose: text = QObject::tr("Missing comma, '}', or ']'"); break; case ErrorMustBeString: text = QObject::tr("The name of an attribute must be a valid character string"); break; case ErrorUnrecognizedToken: text = QObject::tr("The token was not recognized"); break; default: Q_ASSERT(false); } QString errorMsg = QObject::tr("*** Error %1 in QvJson::%2 at position %3 -- %4").arg(error).arg(method).arg(position).arg(text); QStringList errorList; errorList << errorMsg; return QVariant(errorList); } QString QvJson::encodeJson(const QVariant& jsonObject) { QVariant::Type type = jsonObject.type(); switch (type) { case QVariant::Map: return encodeObject(jsonObject); case QVariant::List: return encodeArray(jsonObject); case QVariant::String: return encodeString(jsonObject); case QVariant::Int: case QVariant::Double: return encodeNumeric(jsonObject); case QVariant::Bool: return encodeBool(jsonObject); case QVariant::Invalid: return encodeNull(jsonObject); default: return encodingError("encodeJson", jsonObject, ErrorUnrecognizedObject); } } QString QvJson::encodeObject(const QVariant& jsonObject) { QString result("{ "); QMap<QString, QVariant> map = jsonObject.toMap(); QMapIterator<QString, QVariant> i(map); while (i.hasNext()) { i.next(); result.append(encodeString(i.key())); result.append(" : "); result.append(encodeJson(i.value())); if (i.hasNext()) { result.append(", "); } } result.append(" }"); return result; } QString QvJson::encodeArray(const QVariant& jsonObject) { QString result("[ "); QList<QVariant> list = jsonObject.toList(); for (int i = 0; i < list.count(); i++) { result.append(encodeJson(list.at(i))); if (i+1 < list.count()) { result.append(", "); } } result.append(" ]"); return result; } QString QvJson::encodeString(const QVariant &jsonObject) { return encodeString(jsonObject.toString()); } QString QvJson::encodeString(const QString& value) { QString result = "\""; for (int i = 0; i < value.count(); i++) { ushort chr = value.at(i).unicode(); if (chr < 32) { switch (chr) { case '\b': result.append("\\b"); break; case '\f': result.append("\\f"); break; case '\n': result.append("\\n"); break; case '\r': result.append("\\r"); break; case '\t': result.append("\\t"); break; default: result.append("\\u"); result.append(QString::number(chr, 16).rightJustified(4, '0')); } // End switch } else if (chr > 255) { result.append("\\u"); result.append(QString::number(chr, 16).rightJustified(4, '0')); } else { result.append(value.at(i)); } } result.append('"'); QString displayResult = result; // For debug, since "result" often doesn't show Q_UNUSED(displayResult); return result; } QString QvJson::encodeNumeric(const QVariant& jsonObject) { return jsonObject.toString(); } QString QvJson::encodeBool(const QVariant& jsonObject) { return jsonObject.toString(); } QString QvJson::encodeNull(const QVariant& jsonObject) { return "null"; } QString QvJson::encodingError(const QString& method, const QVariant& jsonObject, Error error) { QString text; switch (error) { case ErrorUnrecognizedObject: text = QObject::tr("Unrecognized object type"); break; default: Q_ASSERT(false); } return QObject::tr("*** Error %1 in QvJson::%2 -- %3").arg(error).arg(method).arg(text); } 
Sign up to request clarification or add additional context in comments.

2 Comments

Not sure copy/pasting yet another Qt json implementation (without included unit tests) from the web will improve the maintainability.
@FrankOsterfeld - Not from the web. From my private stash.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.