Commit df2ae4c9 authored by Haocheng LIU's avatar Haocheng LIU

FEATURE: Add nlohman json support for attribute system

Collection, view, attributeDef, attribute all itemDefs and items now can be serialized
and deserialized via json.
TBD: More test cases should be added to test the serialization process.
parent ef05814f
......@@ -250,6 +250,11 @@ if (NOT CMAKE_INSTALL_RPATH_USE_LINK_PATH)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif ()
################################################################################
# JSON Related Settings
################################################################################
find_package(nlohmann_json REQUIRED)
################################################################################
# Moab Related Settings
################################################################################
......
This source diff could not be displayed because it is stored in LFS. You can view the blob instead.
This source diff could not be displayed because it is stored in LFS. You can view the blob instead.
......@@ -65,6 +65,7 @@ set(smtkCore_private_include_directories
set(smtkCore_public_link_libraries
cJSON
MOAB
nlohmann_json
)
set(smtkCore_private_link_libraries
......
set (jsonAttributeHeaders
json/jsonAttribute.h
json/jsonComponentItem.h
json/jsonComponentItemDefinition.h
json/jsonCollection.h
json/jsonDateTimeItem.h
json/jsonDateTimeItemDefinition.h
json/jsonDirectoryItem.h
json/jsonDirectoryItemDefinition.h
json/jsonDoubleItem.h
json/jsonDoubleItemDefinition.h
json/jsonDefinition.h
json/jsonFileItem.h
json/jsonFileItemDefinition.h
json/jsonFileSystemItem.h
json/jsonFileSystemItemDefinition.h
json/jsonGroupItem.h
json/jsonGroupItemDefinition.h
json/jsonHelperFunction.h
json/jsonIntItem.h
json/jsonIntItemDefinition.h
json/jsonItem.h
json/jsonItemDefinition.h
json/jsonMeshItem.h
json/jsonMeshItemDefinition.h
json/jsonMeshSelectionItem.h
json/jsonMeshSelectionItemDefinition.h
json/jsonModelEntityItem.h
json/jsonModelEntityItemDefinition.h
json/jsonStringItem.h
json/jsonStringItemDefinition.h
json/jsonRefItem.h
json/jsonRefItemDefinition.h
json/jsonValueItem.h
json/jsonValueItemDefinition.h
)
set (jsonAttributeSrcs
json/jsonAttribute.cxx
json/jsonComponentItem.cxx
json/jsonComponentItemDefinition.cxx
json/jsonCollection.cxx
json/jsonDateTimeItem.cxx
json/jsonDateTimeItemDefinition.cxx
json/jsonDirectoryItem.cxx
json/jsonDirectoryItemDefinition.cxx
json/jsonDoubleItem.cxx
json/jsonDoubleItemDefinition.cxx
json/jsonDefinition.cxx
json/jsonFileItem.cxx
json/jsonFileItemDefinition.cxx
json/jsonFileSystemItem.cxx
json/jsonFileSystemItemDefinition.cxx
json/jsonGroupItem.cxx
json/jsonGroupItemDefinition.cxx
json/jsonHelperFunction.cxx
json/jsonIntItem.cxx
json/jsonIntItemDefinition.cxx
json/jsonItem.cxx
json/jsonItemDefinition.cxx
json/jsonMeshItem.cxx
json/jsonMeshItemDefinition.cxx
json/jsonMeshSelectionItem.cxx
json/jsonMeshSelectionItemDefinition.cxx
json/jsonModelEntityItem.cxx
json/jsonModelEntityItemDefinition.cxx
json/jsonStringItem.cxx
json/jsonStringItemDefinition.cxx
json/jsonRefItem.cxx
json/jsonRefItemDefinition.cxx
json/jsonValueItem.cxx
json/jsonValueItemDefinition.cxx
)
set(attributeHeaders
Attribute.h
ComponentItem.h
......@@ -37,9 +110,11 @@ set(attributeHeaders
ValueItemTemplate.h
VoidItem.h
VoidItemDefinition.h
${jsonAttributeHeaders}
)
set(attributeSrcs
${jsonAttributeSrcs}
Attribute.cxx
ComponentItem.cxx
ComponentItemDefinition.cxx
......@@ -86,4 +161,6 @@ endif()
if(SMTK_ENABLE_TESTING)
add_subdirectory(testing)
target_link_libraries(TestBuild_smtk_attribute
PUBLIC nlohmann_json)
endif(SMTK_ENABLE_TESTING)
......@@ -29,6 +29,7 @@
#include "smtk/CoreExports.h"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/ItemDefinition.h"
#include "smtk/attribute/VoidItemDefinition.h"
namespace smtk
{
......
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "jsonAttribute.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/json/jsonHelperFunction.h"
#include "smtk/attribute/json/jsonItem.h"
#include "smtk/attribute/json/jsonModelEntityItem.h"
#include "smtk/io/Logger.h"
#include "smtk/model/Manager.h"
#include "smtk/PublicPointerDefs.h"
#include "json.hpp"
#include <iosfwd>
#include <string>
using json = nlohmann::json;
/**\brief Provide a way to serialize valueItemPtr
*/
namespace smtk
{
namespace attribute
{
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::AttributePtr& att)
{ // Follow the logic in XmlV2StringWriter::processAttribute
j["Name"] = att->name();
if (att->definition())
{
j["Type"] = att->type();
if (att->definition()->isNodal())
{
j["OnInteriorNodes"] = att->appliesToInteriorNodes();
j["OnBoundaryNodes"] = att->appliesToBoundaryNodes();
}
}
j["ID"] = att->id().toString();
// Save associated entities
smtk::attribute::ModelEntityItemPtr assoc = att->associations();
if (assoc && assoc->numberOfValues() > 0)
{
j["Associations"] = assoc;
}
// Save Color Information
if (att->isColorSet())
{
const double* rgba = att->color();
std::vector<double> rgbaV;
rgbaV.push_back(rgba[0]);
rgbaV.push_back(rgba[1]);
rgbaV.push_back(rgba[2]);
rgbaV.push_back(rgba[3]);
j["Color"] = rgbaV;
}
int i, n = static_cast<int>(att->numberOfItems());
if (n)
{
json items = json::array();
for (i = 0; i < n; i++)
{
json item, itemValue;
item["Type"] = Item::type2String(att->item(i)->type());
// TODO Add name check and whether json equals the item of the attribute
smtk::attribute::JsonHelperFunction::processItemTypeToJson(itemValue, att->item(i));
// Same type items can occur multiple times
item["ItemValue"] = itemValue;
items.push_back(item);
}
j["Items"] = items;
}
}
SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::AttributePtr& att,
const smtk::attribute::CollectionPtr& colPtr,
std::vector<smtk::attribute::ItemExpressionInfo>& itemExpressionInfo,
std::vector<smtk::attribute::AttRefInfo>& attRefInfo)
{ // Follow the logic in XmlDocV1Parser::processAttribute::L1753
try
{
att->setAppliesToInteriorNodes(j.at("OnInteriorNodes"));
}
catch (std::exception& /*e*/)
{
}
try
{
att->setAppliesToBoundaryNodes(j.at("OnBoundaryNodes"));
}
catch (std::exception& /*e*/)
{
}
try
{
std::vector<double> colorV = j.at("Color");
double color[4];
for (int i = 0; i < 4; i++)
{
color[i] = colorV[i];
}
att->setColor(color);
}
catch (std::exception& /*e*/)
{
}
try
{
std::vector<double> colorV = j.at("Color");
double color[4];
for (int i = 0; i < 4; i++)
{
color[i] = colorV[i];
}
att->setColor(color);
}
catch (std::exception& /*e*/)
{
}
// Process items
json items;
try
{
items = j.at("Items");
}
catch (std::exception& /*e*/)
{
}
if (!items.is_null())
{
int i = 0;
for (auto itemIter = items.begin(); itemIter != items.end(); itemIter++, i++)
{
try
{
json itemJson = itemIter->at("ItemValue");
auto itemToProcess = att->item(i);
smtk::attribute::JsonHelperFunction::processItemTypeFromJson(
itemJson, itemToProcess, colPtr, itemExpressionInfo, attRefInfo);
}
catch (std::exception& /*e*/)
{
}
}
}
// Process items
json association;
try
{
association = j.at("Associations");
}
catch (std::exception& /*e*/)
{
}
if (!association.is_null())
{
smtk::attribute::ModelEntityItem::Ptr assocsItem = att->associations();
smtk::attribute::from_json(association, assocsItem, colPtr);
// Now the ModelEntityItem is deserialized but we need
// to let the model manager know about the associations
// (assuming we have a model manager):
smtk::model::Manager::Ptr mmgr = att->modelManager();
if (mmgr)
{
smtk::attribute::ModelEntityItem::const_iterator eit;
for (eit = assocsItem->begin(); eit != assocsItem->end(); ++eit)
{
// Calling associateAttribute() with a NULL attribute collection
// prevents the model manager from attempting to add the association
// back to the attribute we are currently deserializing:
mmgr->associateAttribute(NULL, att->id(), eit->entity());
}
}
}
}
}
}
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_attribute_jsonAttribute_h
#define smtk_attribute_jsonAttribute_h
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/json/jsonHelperFunction.h"
#include "smtk/attribute/json/jsonItem.h"
#include "smtk/attribute/json/jsonModelEntityItem.h"
#include "smtk/io/Logger.h"
#include "smtk/model/Manager.h"
#include "smtk/PublicPointerDefs.h"
#include "json.hpp"
#include <iosfwd>
#include <string>
using json = nlohmann::json;
/**\brief Provide a way to serialize valueItemPtr
*/
namespace smtk
{
namespace attribute
{
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::AttributePtr& att);
SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::AttributePtr& att,
const smtk::attribute::CollectionPtr& colPtr,
std::vector<smtk::attribute::ItemExpressionInfo>& itemExpressionInfo,
std::vector<smtk::attribute::AttRefInfo>& attRefInfo);
}
}
#endif
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "jsonCollection.h"
#include "json.hpp"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/Collection.h"
#include "smtk/attribute/json/jsonDefinition.h"
#include "smtk/io/Logger.h"
#include "smtk/view/json/jsonView.h"
#include "smtk/CoreExports.h"
#include <string>
namespace smtk
{
namespace attribute
{
using ItemExpressionDefInfo = std::pair<smtk::attribute::ValueItemDefinitionPtr, std::string>;
using AttRefDefInfo = std::pair<smtk::attribute::RefItemDefinitionPtr, std::string>;
using json = nlohmann::json;
/**\brief Provide a way to serialize Collection. It would stick with attribute
* V3 format
*/
/// Convert a SelectionManager's currentSelection() to JSON.
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::CollectionPtr& col)
{
//TODO: write some meta data?
// Write out the category and analysis information
if (col->numberOfCategories())
{
// When parsing, it might has a default value, so here a value object is added
j["Categories"]["Value"] = col->categories();
}
if (col->numberOfAnalyses())
{
j["Analyses"] = col->analyses();
}
// Write out the advance levels information
if (col->numberOfAdvanceLevels())
{
json advanceLevelsObj = json::object();
const std::map<int, std::string>& levels = col->advanceLevels();
for (auto iter = levels.begin(); iter != levels.end(); iter++)
{
int intLevel = iter->first;
json intLevelObj = json::object();
// Json mandates key to be string
intLevelObj["Label"] = iter->second;
const double* rgba = col->advanceLevelColor(intLevel);
if (rgba)
{
intLevelObj["Color"] = { rgba[0], rgba[1], rgba[2], rgba[3] };
advanceLevelsObj[std::to_string(intLevel)] = intLevelObj;
}
}
j["AdvanceLevels"] = advanceLevelsObj;
}
// In Xml we have control over including definitions, instances,
// modelInformation and views.
// Process attribute info
std::vector<smtk::attribute::DefinitionPtr> definitionPtrs;
col->definitions(definitionPtrs);
// a list of defObj
j["Definitions"] = definitionPtrs;
// Process views
// First write toplevel views and then write out the non-toplevel - note that the
// attribute or view collection do care about this - the assumption
// is that the designer would probably like all the toplevel views clustered together
json viewsObj = json::array();
bool isTop;
for (auto iter = col->views().begin(); iter != col->views().end(); iter++)
{
if (!(iter->second->details().attributeAsBool("TopLevel", isTop) && isTop))
{
continue;
}
viewsObj.push_back(iter->second);
}
for (auto iter = col->views().begin(); iter != col->views().end(); iter++)
{
if ((iter->second->details().attributeAsBool("TopLevel", isTop) && isTop))
{
continue;
}
viewsObj.push_back(iter->second);
}
j["Views"] = viewsObj;
// Process model info
}
SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::CollectionPtr& col)
{
std::vector<smtk::attribute::ItemExpressionDefInfo> expressDefInfo;
std::vector<smtk::attribute::AttRefDefInfo> refDefInfo;
smtk::io::Logger logger;
//TODO: v2Parser has a notion of rootName
if (!col.get() || j.is_null())
{
// Create a valid collectionPtr so we can assign it to someone else
col = smtk::attribute::Collection::create();
}
// Process Analysis Info
// nlohmman's get function does not support nested map, so iterator is used
try
{
json analyses = j.at("Analyses");
for (json::iterator iterAna = analyses.begin(); iterAna != analyses.end(); iterAna++)
{
col->defineAnalysis(iterAna.key(), iterAna.value());
}
}
catch (std::exception& /*e*/)
{
}
//Process AdvanceLevel info
try
{
json advanceLevels = j.at("AdvanceLevels");
for (auto iterAdv = advanceLevels.begin(); iterAdv != advanceLevels.end(); iterAdv++)
{
int level = std::stoi(iterAdv.key());
json levelObj = iterAdv.value();
std::vector<double> rgba = levelObj.at("Color");
std::string label = levelObj.at("Label");
double color[4];
for (int i = 0; i < 4; i++)
{
color[i] = rgba[i];
}
col->addAdvanceLevel(level, label);
col->setAdvanceLevelColor(level, color);
}
}
catch (std::exception& /*e*/)
{
}
// Process attribute info
json defininitions;
try
{
defininitions = j.at("Definitions");
}
catch (std::exception& /*e*/)
{
}
if (!defininitions.is_null())
{
for (auto iterDef = defininitions.begin(); iterDef != defininitions.end(); iterDef++)
{
try
{
smtk::attribute::DefinitionPtr def, baseDef;
json currentDef = *iterDef;
// Get type and baseDef info
std::string type = currentDef.at("Type");
if (type.empty())
{
smtkErrorMacro(logger, "Definition missing Type XML Attribute");
continue;
}
std::string baseType = currentDef.at("BaseType").is_null() ? "" : currentDef.at("BaseType");
if (!baseType.empty())
{
baseDef = col->findDefinition(baseType);
if (!baseDef)
{
smtkErrorMacro(logger, "Could not find Base Definition: "
<< baseType << " needed to create Definition: " << type);
continue;
}
def = col->createDefinition(type, baseDef);
}
else
{
def = col->createDefinition(type);
}
if (!def)
{
smtkWarningMacro(logger, "Definition: " << type << " already exists in the Collection");
continue;
}
// process the definition
// Since definition is not default constructible, we have to call the
// function directly
// expressionDefInfo, refDefInfo and attributes are handled in jsonDefinition
smtk::attribute::from_json(currentDef, def, expressDefInfo, refDefInfo);
}
catch (std::exception& /*e*/)
{
}
}
}
// Proces view info
try
{
json views = j.at("Views");
for (auto iterView = views.begin(); iterView != views.end(); iterView++)
{
smtk::view::ViewPtr view = *iterView;
col->addView(view);
}
}
catch (std::exception& /*e*/)
{
}
// Process model info
// Update category infomration
col->updateCategories();
}
}
}
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#ifndef smtk_attribute_jsonCollection_h
#define smtk_attribute_jsonCollection_h
#include "json.hpp"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/Collection.h"
#include "smtk/attribute/json/jsonDefinition.h"
#include "smtk/io/Logger.h"
#include "smtk/view/json/jsonView.h"
#include "smtk/CoreExports.h"
#include <string>
namespace smtk
{
namespace attribute
{
using ItemExpressionDefInfo = std::pair<smtk::attribute::ValueItemDefinitionPtr, std::string>;
using AttRefDefInfo = std::pair<smtk::attribute::RefItemDefinitionPtr, std::string>;
using json = nlohmann::json;
/**\brief Provide a way to serialize Collection. It would stick with attribute
* V3 format
*/
/// Convert a SelectionManager's currentSelection() to JSON.
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::CollectionPtr& col);
SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::CollectionPtr& col);
}
}
#endif
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//=========================================================================
#include "jsonComponentItem.h"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/Collection.h"
#include "smtk/attribute/ComponentItem.h"
#include "smtk/attribute/json/jsonItem.h"
#include "smtk/resource/Manager.h"
#include "smtk/resource/Resource.h"
#include "json.hpp"
#include <exception>
#include <string>
using json = nlohmann::json;
/**\brief Provide a way to serialize ComponentItemPtr
*/
namespace smtk
{
namespace attribute
{
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ComponentItemPtr& itemPtr)
{
smtk::attribute::to_json(j, smtk::dynamic_pointer_cast<Item>(itemPtr));
size_t i = 0, n = itemPtr->numberOfValues();
std::size_t numRequiredVals = itemPtr->numberOfRequiredValues();
if (!n)
{
return;
}
if ((numRequiredVals == 1) && (!itemPtr->isExtensible()))
{
auto rsrcPtr = itemPtr->value(i)->resource();
if (itemPtr->isSet() && rsrcPtr)
{