Commit be2f3197 authored by Haocheng LIU's avatar Haocheng LIU

Fix attribute writer and reader

This commit fixes several bugs in attribute Json de/serializers.
* Handle voidItem and voidItemDefinition
* Set number of groups in GroupItem
* Refactor the logic of jsonResource
* Fix a Json serialization and deserialization test
parent 8ea79422
Pipeline #126072 passed with stage
# Fix the json attribute serializer and deserializer
This commit fixes several bugs in attribute Json de/serializers.
* Handle voidItem and voidItemDefinition
* Set number of groups in GroupItem
* Refractor the logic of jsonResource
* Fix a Json serialization and deserialization test
......@@ -35,6 +35,8 @@ set(jsonAttributeHeaders
json/jsonRefItemDefinition.h
json/jsonValueItem.h
json/jsonValueItemDefinition.h
json/jsonVoidItem.h
json/jsonVoidItemDefinition.h
)
set(jsonAttributeSrcs
......@@ -74,6 +76,8 @@ set(jsonAttributeSrcs
json/jsonRefItemDefinition.cxx
json/jsonValueItem.cxx
json/jsonValueItemDefinition.cxx
json/jsonVoidItem.cxx
json/jsonVoidItemDefinition.cxx
)
set(attributeHeaders
......
......@@ -50,6 +50,21 @@ class SMTKCORE_EXPORT Definition : public smtk::enable_shared_from_this<Definiti
{
public:
smtkTypeMacroBase(smtk::attribute::Definition);
struct SMTKCORE_EXPORT WeakDefinitionPtrCompare
{
bool operator()(const smtk::attribute::WeakDefinitionPtr& lhs,
const smtk::attribute::WeakDefinitionPtr& rhs) const
{
auto left = lhs.lock();
if (left == nullptr)
return true;
auto right = rhs.lock();
if (right == nullptr)
return false;
return left->type() < right->type();
}
};
virtual ~Definition();
// Description:
......
......@@ -315,15 +315,12 @@ void Resource::internalFindAttributes(
result.insert(result.end(), it->second.begin(), it->second.end());
}
}
std::map<smtk::attribute::DefinitionPtr, smtk::attribute::WeakDefinitionPtrSet>::const_iterator
dit;
dit = m_derivedDefInfo.find(def);
auto dit = m_derivedDefInfo.find(def);
if (dit == m_derivedDefInfo.end())
{
return;
}
smtk::attribute::WeakDefinitionPtrSet::const_iterator defIt;
for (defIt = dit->second.begin(); defIt != dit->second.end(); defIt++)
for (auto defIt = dit->second.begin(); defIt != dit->second.end(); defIt++)
{
this->internalFindAttributes(defIt->lock(), result);
}
......@@ -346,15 +343,12 @@ void Resource::internalFindAllDerivedDefinitions(smtk::attribute::DefinitionPtr
{
result.push_back(def);
}
std::map<smtk::attribute::DefinitionPtr, smtk::attribute::WeakDefinitionPtrSet>::const_iterator
dit;
dit = m_derivedDefInfo.find(def);
auto dit = m_derivedDefInfo.find(def);
if (dit == m_derivedDefInfo.end())
{
return;
}
smtk::attribute::WeakDefinitionPtrSet::const_iterator defIt;
for (defIt = dit->second.begin(); defIt != dit->second.end(); defIt++)
for (auto defIt = dit->second.begin(); defIt != dit->second.end(); defIt++)
{
this->internalFindAllDerivedDefinitions(defIt->lock(), onlyConcrete, result);
}
......@@ -434,8 +428,7 @@ void Resource::updateCategories()
def = toBeProcessed.front();
def->setCategories();
// Does this definition have derived defs from it?
std::map<smtk::attribute::DefinitionPtr, smtk::attribute::WeakDefinitionPtrSet>::iterator dit =
m_derivedDefInfo.find(def);
auto dit = m_derivedDefInfo.find(def);
if (dit != m_derivedDefInfo.end())
{
smtk::attribute::WeakDefinitionPtrSet::iterator ddit;
......@@ -458,18 +451,15 @@ void Resource::updateCategories()
void Resource::derivedDefinitions(
smtk::attribute::DefinitionPtr def, std::vector<smtk::attribute::DefinitionPtr>& result) const
{
std::map<smtk::attribute::DefinitionPtr, smtk::attribute::WeakDefinitionPtrSet>::const_iterator
it;
it = m_derivedDefInfo.find(def);
auto it = m_derivedDefInfo.find(def);
result.clear();
if (it == m_derivedDefInfo.end())
{
return;
}
std::size_t i, n = it->second.size();
std::size_t i(0), n = it->second.size();
result.resize(n);
smtk::attribute::WeakDefinitionPtrSet::const_iterator dit;
for (i = 0, dit = it->second.begin(); i < n; dit++, i++)
for (auto dit = it->second.begin(); i < n; dit++, i++)
{
result[i] = dit->lock();
}
......@@ -530,10 +520,9 @@ bool Resource::disassociate(const smtk::resource::ResourcePtr& resource)
void Resource::updateDerivedDefinitionIndexOffsets(smtk::attribute::DefinitionPtr def)
{
WeakDefinitionPtrSet ddefs = m_derivedDefInfo[def];
WeakDefinitionPtrSet::iterator iter;
auto ddefs = m_derivedDefInfo[def];
smtk::attribute::DefinitionPtr d;
for (iter = ddefs.begin(); iter != ddefs.end(); ++iter)
for (auto iter = ddefs.begin(); iter != ddefs.end(); ++iter)
{
d = iter->lock();
if (!d)
......
......@@ -22,6 +22,7 @@
#include "smtk/CoreExports.h"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/Definition.h"
#include "smtk/attribute/DirectoryInfo.h"
#include "smtk/attribute/Item.h"
#include "smtk/attribute/ItemDefinition.h"
......@@ -224,7 +225,10 @@ protected:
std::map<std::string, std::set<smtk::attribute::AttributePtr> > m_attributeClusters;
std::map<std::string, smtk::attribute::AttributePtr> m_attributes;
std::map<smtk::common::UUID, smtk::attribute::AttributePtr> m_attributeIdMap;
std::map<smtk::attribute::DefinitionPtr, smtk::attribute::WeakDefinitionPtrSet> m_derivedDefInfo;
std::map<smtk::attribute::DefinitionPtr,
std::set<smtk::attribute::WeakDefinitionPtr, Definition::WeakDefinitionPtrCompare> >
m_derivedDefInfo;
std::set<std::string> m_categories;
std::map<std::string, std::set<std::string> > m_analyses;
std::map<std::string, smtk::view::ViewPtr> m_views;
......
......@@ -13,6 +13,7 @@
#include "smtk/attribute/json/jsonHelperFunction.h"
#include "smtk/attribute/json/jsonItem.h"
#include "smtk/common/UUID.h"
#include "smtk/io/Logger.h"
#include "smtk/model/Resource.h"
......@@ -82,6 +83,15 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::AttributePtr& att
std::vector<smtk::attribute::ItemExpressionInfo>& itemExpressionInfo,
std::vector<smtk::attribute::AttRefInfo>& attRefInfo)
{ // Follow the logic in XmlDocV1Parser::processAttribute::L1753
try
{
std::string uuidString = j.at("ID");
auto uuid = smtk::common::UUID(uuidString);
att->setId(uuid);
}
catch (std::exception& /*e*/)
{
}
try
{
att->setAppliesToInteriorNodes(j.at("OnInteriorNodes"));
......@@ -140,6 +150,10 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::AttributePtr& att
try
{
auto itemToProcess = att->find(itemIter->at("Name"));
if (!itemToProcess)
{
continue;
}
smtk::attribute::JsonHelperFunction::processItemTypeFromJson(
*itemIter, itemToProcess, itemExpressionInfo, attRefInfo);
}
......
......@@ -113,23 +113,10 @@ SMTKCORE_EXPORT void to_json(nlohmann::json& j, const smtk::attribute::Definitio
smtk::attribute::ItemDefinitionPtr itemDPtr = defPtr->itemDefinition(static_cast<int>(i));
smtk::attribute::JsonHelperFunction::processItemDefinitionTypeToJson(itemDef, itemDPtr);
// Same type definitions can occur multiple times
itemDefs[Item::type2String(itemDPtr->type())].push_back(itemDef);
itemDefs.push_back(itemDef);
}
j["ItemDefinitions"] = itemDefs;
}
// Process all attributes based on this class
std::vector<smtk::attribute::AttributePtr> atts;
smtk::attribute::ResourcePtr resource =
std::dynamic_pointer_cast<smtk::attribute::Resource>(defPtr->resource());
resource->findDefinitionAttributes(defPtr->type(), atts);
// TODO: process Attributes
j["Attributes"] = atts;
// Now process all of its derived classes
std::vector<smtk::attribute::DefinitionPtr> derivedDefPtrs;
resource->derivedDefinitions(defPtr, derivedDefPtrs);
j["DerivedDefinitions"] = derivedDefPtrs;
}
SMTKCORE_EXPORT void from_json(const nlohmann::json& j, smtk::attribute::DefinitionPtr& defPtr,
......@@ -292,145 +279,6 @@ SMTKCORE_EXPORT void from_json(const nlohmann::json& j, smtk::attribute::Definit
catch (std::exception& /*e*/)
{
}
// At this point we have all the definitions read in so lets
// fix up all of the attribute definition references
// Reference: XmlDovV1Parser::L575
attribute::DefinitionPtr def;
smtk::attribute::ResourcePtr resource =
std::dynamic_pointer_cast<smtk::attribute::Resource>(defPtr->resource());
for (size_t i = 0; i < expressionDefInfo.size(); i++)
{
def = resource->findDefinition(expressionDefInfo[i].second);
if (def)
{
expressionDefInfo[i].first->setExpressionDefinition(def);
}
else
{
std::cerr << "Referenced Item expression Definition: " << expressionDefInfo[i].second
<< " is missing and required by Item Definition: "
<< expressionDefInfo[i].first->name() << std::endl;
}
}
json attributes;
try
{
attributes = j.at("Attributes");
}
catch (std::exception& /*e*/)
{
}
std::vector<ItemExpressionInfo> itemExpressionInfo;
std::vector<AttRefInfo> attRefInfo;
if (!attributes.is_null())
{
for (auto iter = attributes.begin(); iter != attributes.end(); iter++)
{ // Get/Create the attribute first
std::string name, type;
smtk::attribute::AttributePtr att;
smtk::common::UUID id;
try
{
name = iter->at("Name");
}
catch (std::exception& /*e*/)
{
}
if (name.empty())
{
std::cerr << "Invalid Attribute! - Missing json Attribute Name" << std::endl;
continue;
}
try
{
type = iter->at("Type");
}
catch (std::exception& /*e*/)
{
}
if (type.empty())
{
std::cerr << "Invalid Attribute! - Missing json Attribute type" << std::endl;
continue;
}
smtk::common::UUID uuid = smtk::common::UUID::null();
try
{
std::string temp = iter->at("ID");
uuid = smtk::common::UUID(temp);
}
catch (std::exception& /*e*/)
{
};
def = colPtr->findDefinition(type);
if (!def)
{
std::cerr << "Attribute: " << name << " of Type: " << type
<< " - can not find attribute definition" << std::endl;
continue;
}
// Is the definition abstract?
if (def->isAbstract())
{
std::cerr << "Attribute: " << name << " of Type: " << type
<< " - is based on an abstract definition" << std::endl;
continue;
}
// Do we have a valid uuid?
if (id.isNull())
{
att = colPtr->createAttribute(name, def);
}
else
{
att = colPtr->createAttribute(name, def, id);
}
if (!att)
{
std::cerr << "Attribute: " << name << " of Type: " << type
<< " - could not be created - is the name in use" << std::endl;
return;
}
smtk::attribute::from_json(*iter, att, itemExpressionInfo, attRefInfo);
}
}
// At this point we have all the attributes read in so lets
// fix up all of the attribute references
attribute::AttributePtr att;
for (size_t i = 0; i < itemExpressionInfo.size(); i++)
{
att = colPtr->findAttribute(itemExpressionInfo[i].expName);
if (att)
{
itemExpressionInfo[i].item->setExpression(itemExpressionInfo[i].pos, att);
}
else
{
std::cerr << "Expression Attribute: " << itemExpressionInfo[i].expName
<< " is missing and required by Item : " << itemExpressionInfo[i].item->name()
<< std::endl;
}
}
for (size_t i = 0; i < attRefInfo.size(); i++)
{
att = colPtr->findAttribute(attRefInfo[i].attName);
if (att)
{
attRefInfo[i].item->setValue(attRefInfo[i].pos, att);
}
else
{
std::cerr << "Referenced Attribute: " << attRefInfo[i].attName
<< " is missing and required by Item: " << attRefInfo[i].item->name() << std::endl;
}
}
}
}
}
......@@ -118,6 +118,7 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::GroupItemPtr& ite
try
{
n = j.at("NumberOfGroups");
itemPtr->setNumberOfGroups(n);
}
catch (std::exception& /*e*/)
{
......
......@@ -67,11 +67,10 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::GroupItemDefinition
for (i = 0; i < n; i++)
{
json itemDef;
std::string name = Item::type2String(defPtr->itemDefinition(i)->type());
smtk::attribute::JsonHelperFunction::processItemDefinitionTypeToJson(
itemDef, defPtr->itemDefinition(i));
// Same type definitions can occur multiple times
itemDefs[name].push_back(itemDef);
itemDefs.push_back(itemDef);
}
j["ItemDefinitions"] = itemDefs;
}
......@@ -89,6 +88,27 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::GroupItemDefiniti
auto temp = smtk::dynamic_pointer_cast<ItemDefinition>(defPtr);
smtk::attribute::from_json(j, temp);
try
{
defPtr->setNumberOfRequiredGroups(j.at("NumberOfRequiredGroups"));
}
catch (std::exception)
{
}
try
{
defPtr->setIsExtensible(j.at("Extensible"));
}
catch (std::exception)
{
}
try
{
defPtr->setMaxNumberOfGroups(j.at("MaxNumberOfGroups"));
}
catch (std::exception)
{
}
json clabels;
try
{
......
This diff is collapsed.
......@@ -23,7 +23,7 @@
#include <string>
using json = nlohmann::json;
/**\brief Provide a way to serialize RefItemDefinition
/**\brief Provide a way to serialize RefItemDefinitionPtr
*/
namespace smtk
{
......
......@@ -10,7 +10,9 @@
#include "jsonResource.h"
#include "nlohmann/json.hpp"
#include "smtk/PublicPointerDefs.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/json/jsonAttribute.h"
#include "smtk/attribute/json/jsonDefinition.h"
#include "smtk/io/Logger.h"
#include "smtk/resource/json/jsonResource.h"
......@@ -18,6 +20,7 @@
#include "smtk/CoreExports.h"
#include <queue>
#include <string>
namespace smtk
......@@ -37,7 +40,6 @@ using json = nlohmann::json;
SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
{
smtk::resource::to_json(j, smtk::static_pointer_cast<smtk::resource::Resource>(res));
//TODO: write some meta data?
// Write out the category and analysis information
if (res->numberOfCategories())
{
......@@ -73,11 +75,37 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
// In Xml we have control over including definitions, instances,
// modelInformation and views.
// Process attribute info
std::vector<smtk::attribute::DefinitionPtr> definitionPtrs;
res->definitions(definitionPtrs);
// a list of defObj
j["Definitions"] = definitionPtrs;
// Process definifions from base to derived so that
// when deserializing defs the base def would be available when processing
// derived defs. Attributes are also processed in the loop for simplicity.
std::vector<smtk::attribute::DefinitionPtr> baseDefPtrs, derivedDefPtrs;
res->findBaseDefinitions(baseDefPtrs);
json defsObj = json::array();
json attsObj = json::array();
std::queue<smtk::attribute::DefinitionPtr, std::deque<smtk::attribute::DefinitionPtr> > defsQueue(
std::deque<smtk::attribute::DefinitionPtr>(baseDefPtrs.begin(), baseDefPtrs.end()));
while (!defsQueue.empty())
{
smtk::attribute::DefinitionPtr currentDef = defsQueue.front();
defsObj.push_back(currentDef);
std::vector<smtk::attribute::AttributePtr> atts;
res->findDefinitionAttributes(currentDef->type(), atts);
for (const auto& att : atts)
{
attsObj.push_back(att);
}
defsQueue.pop();
res->derivedDefinitions(currentDef, derivedDefPtrs);
for (const auto& derivedDefPtr : derivedDefPtrs)
{
defsQueue.push(derivedDefPtr);
}
}
j["Definitions"] = defsObj;
j["Attributes"] = attsObj;
// Process views
// First write toplevel views and then write out the non-toplevel - note that the
......@@ -108,8 +136,8 @@ SMTKCORE_EXPORT void to_json(json& j, const smtk::attribute::ResourcePtr& res)
SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::ResourcePtr& res)
{
std::vector<smtk::attribute::ItemExpressionDefInfo> expressDefInfo;
std::vector<smtk::attribute::AttRefDefInfo> refDefInfo;
std::vector<smtk::attribute::ItemExpressionDefInfo> expressionDefInfo;
std::vector<smtk::attribute::AttRefDefInfo> attRefDefInfo;
smtk::io::Logger logger;
//TODO: v2Parser has a notion of rootName
if (!res.get() || j.is_null())
......@@ -159,16 +187,9 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::ResourcePtr& res)
}
// Process attribute info
json definitions;
try
{
definitions = j.at("Definitions");
}
catch (std::exception& /*e*/)
{
}
if (!definitions.is_null())
{
json definitions = j.at("Definitions");
for (auto iterDef = definitions.begin(); iterDef != definitions.end(); iterDef++)
{
try
......@@ -206,14 +227,164 @@ SMTKCORE_EXPORT void from_json(const json& j, smtk::attribute::ResourcePtr& res)
// 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);
smtk::attribute::from_json(currentDef, def, expressionDefInfo, attRefDefInfo);
}
catch (std::exception& /*e*/)
{
std::cerr << "Failed to find type of a definition for resource " << res->name()
<< std::endl;
}
}
}
catch (std::exception& /*e*/)
{
std::cerr << "Failed to find definitions for resource " << res->name() << std::endl;
}
// At this point we have all the definitions read in so lets
// fix up all of the attribute definition references
// Reference: XmlDovV1Parser::L575
smtk::attribute::DefinitionPtr def;
for (size_t i = 0; i < expressionDefInfo.size(); i++)
{
def = res->findDefinition(expressionDefInfo[i].second);
if (def)
{
expressionDefInfo[i].first->setExpressionDefinition(def);
}
else
{
std::cerr << "Referenced Item expression Definition: " << expressionDefInfo[i].second
<< " is missing and required by Item Definition: "
<< expressionDefInfo[i].first->name() << std::endl;
}
}
for (size_t i = 0; i < attRefDefInfo.size(); i++)
{
def = res->findDefinition(attRefDefInfo[i].second);
if (def)
{
attRefDefInfo[i].first->setAttributeDefinition(def);
}
else
{
std::cerr << "Referenced Attribute Definition: " << attRefDefInfo[i].second
<< " is missing and required by Item Definition: " << attRefDefInfo[i].first->name()
<< std::endl;
}
}
// Process attributes info
std::vector<ItemExpressionInfo> itemExpressionInfo;
std::vector<AttRefInfo> attRefInfo;
smtk::attribute::AttributePtr att;
try
{
json attributes = j.at("Attributes");
for (auto iter = attributes.begin(); iter != attributes.end(); iter++)
{ // Get/Create the attribute first
std::string name, type;
smtk::common::UUID id;
try
{
name = iter->at("Name");
}
catch (std::exception& /*e*/)
{
}
if (name.empty())
{
std::cerr << "Invalid Attribute! - Missing json Attribute Name" << std::endl;
continue;
}
try
{
type = iter->at("Type");
}
catch (std::exception& /*e*/)
{
}
if (type.empty())
{
std::cerr << "Invalid Attribute! - Missing json Attribute type" << std::endl;
continue;
}
smtk::common::UUID uuid = smtk::common::UUID::null();
try
{
std::string uuidString = iter->at("ID");
uuid = smtk::common::UUID(uuidString);
}
catch (std::exception& /*e*/)
{
};
def = res->findDefinition(type);
if (!def)
{
std::cerr << "Attribute: " << name << " of Type: " << type
<< " - can not find attribute definition" << std::endl;
continue;
}
// Is the definition abstract?
if (def->isAbstract())
{
std::cerr << "Attribute: " << name << " of Type: " << type
<< " - is based on an abstract definition" << std::endl;
continue;
}
if (id.isNull())
{