Commit 1a397e99 authored by Gigg, Martyn Anthony's avatar Gigg, Martyn Anthony
Browse files

Add a Property::asJSON method

Converts a property object into a Json representation for serialization
Refs #23988
parent 1ec2f062
......@@ -271,7 +271,7 @@ public:
/// Serialize an object to a string
std::string toString() const override;
/// Serialize an object to a json object
::Json::Value toJson() const;
::Json::Value toJson() const override;
/// De-serialize an object from a string
static IAlgorithm_sptr fromString(const std::string &input);
/// Construct an object from a history entry
......
......@@ -64,6 +64,8 @@ public:
}
/// Return the algorithm as string
std::string value() const override;
/// Create a Json::Value from the algorithm value
Json::Value valueAsJson() const override;
/// Get the default
std::string getDefault() const override;
/// Sets the value of the algorithm
......
......@@ -149,10 +149,12 @@ public:
/// setting the child end progress
void setChildEndProgress(const double endProgress) const override;
/** @name String serialization */
/** @name Serialization */
//@{
/// Serialize an object to a string
std::string toString() const override;
/// Serialize as a json value
Json::Value toJson() const override;
//@}
private:
......
......@@ -56,6 +56,9 @@ public:
/// Get the function definition string
std::string value() const override;
/// Return a Json::Value object encoding the function string
Json::Value valueAsJson() const override;
/// Get the value the property was initialised with -its default value
std::string getDefault() const override;
......
......@@ -168,6 +168,11 @@ public:
virtual void setChildEndProgress(const double endProgress) const = 0;
/// Serialize an algorithm
virtual std::string toString() const = 0;
/// Serialize an algorithm as Json
virtual ::Json::Value toJson() const = 0;
private:
using Kernel::IPropertyManager::asJson;
};
} // namespace API
......
......@@ -88,6 +88,8 @@ public:
std::string value() const override;
Json::Value valueAsJson() const override;
bool isValueSerializable() const override;
std::string getDefault() const override;
......
......@@ -5,27 +5,29 @@
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidAPI/Workspace.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/PropertyHistory.h"
#include "MantidKernel/Strings.h"
#include <json/value.h>
namespace Mantid {
namespace API {
/** Constructor.
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
template <typename TYPE>
WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
const std::string &wsName,
......@@ -37,17 +39,17 @@ WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
m_optional(PropertyMode::Mandatory), m_locking(LockMode::Lock) {}
/** Constructor.
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param optional :: If true then the property is optional
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param optional :: If true then the property is optional
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
template <typename TYPE>
WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
const std::string &wsName,
......@@ -60,21 +62,21 @@ WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
m_locking(LockMode::Lock) {}
/** Constructor.
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param optional :: A boolean indicating whether the property is mandatory
* or not. Only matters
* for input properties
* @param locking :: A boolean indicating whether the workspace should read or
* write-locked when an algorithm begins. Default=true.
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
* Sets the property and workspace names but initializes the workspace pointer
* to null.
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output
* or Direction::InOut (Input & Output) workspace
* @param optional :: A boolean indicating whether the property is mandatory
* or not. Only matters
* for input properties
* @param locking :: A boolean indicating whether the workspace should read or
* write-locked when an algorithm begins. Default=true.
* @param validator :: The (optional) validator to use for this property
* @throw std::out_of_range if the direction argument is not a member of the
* Direction enum (i.e. 0-2)
*/
template <typename TYPE>
WorkspaceProperty<TYPE>::WorkspaceProperty(const std::string &name,
const std::string &wsName,
......@@ -140,12 +142,20 @@ WorkspaceProperty<TYPE> *WorkspaceProperty<TYPE>::clone() const {
}
/** Get the name of the workspace
* @return The workspace's name
*/
* @return The workspace's name
*/
template <typename TYPE> std::string WorkspaceProperty<TYPE>::value() const {
return m_workspaceName;
}
/**
* @returns The name of the workspace encode as a Json::Value
*/
template <typename TYPE>
Json::Value WorkspaceProperty<TYPE>::valueAsJson() const {
return Json::Value(value());
}
/** Returns true if the workspace is in the ADS or there is none.
* @return true if the string returned by value() is valid
*/
......@@ -155,18 +165,18 @@ bool WorkspaceProperty<TYPE>::isValueSerializable() const {
}
/** Get the value the property was initialised with -its default value
* @return The default value
*/
* @return The default value
*/
template <typename TYPE>
std::string WorkspaceProperty<TYPE>::getDefault() const {
return m_initialWSName;
}
/** Set the name of the workspace.
* Also tries to retrieve it from the AnalysisDataService.
* @param value :: The new name for the workspace
* @return
*/
* Also tries to retrieve it from the AnalysisDataService.
* @param value :: The new name for the workspace
* @return
*/
template <typename TYPE>
std::string WorkspaceProperty<TYPE>::setValue(const std::string &value) {
m_workspaceName = value;
......@@ -198,12 +208,12 @@ std::string WorkspaceProperty<TYPE>::setDataItem(
}
/** Checks whether the entered workspace is valid.
* To be valid, in addition to satisfying the conditions of any validators,
* an output property must not have an empty name and an input one must point
* to
* a workspace of the correct type.
* @returns A user level description of the problem or "" if it is valid.
*/
* To be valid, in addition to satisfying the conditions of any validators,
* an output property must not have an empty name and an input one must point
* to
* a workspace of the correct type.
* @returns A user level description of the problem or "" if it is valid.
*/
template <typename TYPE> std::string WorkspaceProperty<TYPE>::isValid() const {
// start with the no error condition
std::string error;
......@@ -264,9 +274,9 @@ template <typename TYPE> std::string WorkspaceProperty<TYPE>::isValid() const {
}
/** Indicates if the object is still pointing to the same workspace
* @return true if the value is the same as the initial value or false
* otherwise
*/
* @return true if the value is the same as the initial value or false
* otherwise
*/
template <typename TYPE> bool WorkspaceProperty<TYPE>::isDefault() const {
if (m_initialWSName.empty()) {
return m_workspaceName.empty() && !this->m_value;
......@@ -338,9 +348,9 @@ const Kernel::PropertyHistory WorkspaceProperty<TYPE>::createHistory() const {
}
/** If this is an output workspace, store it into the AnalysisDataService
* @return True if the workspace is an output workspace and has been stored
* @throw std::runtime_error if unable to store the workspace successfully
*/
* @return True if the workspace is an output workspace and has been stored
* @throw std::runtime_error if unable to store the workspace successfully
*/
template <typename TYPE> bool WorkspaceProperty<TYPE>::store() {
bool result = false;
if (!this->operator()() && isOptional())
......@@ -376,10 +386,10 @@ void WorkspaceProperty<TYPE>::setIsMasterRank(bool isMasterRank) {
}
/** Checks whether the entered workspace group is valid.
* To be valid *all* members of the group have to be valid.
* @param wsGroup :: the WorkspaceGroup of which to check the validity
* @returns A user level description of the problem or "" if it is valid.
*/
* To be valid *all* members of the group have to be valid.
* @param wsGroup :: the WorkspaceGroup of which to check the validity
* @returns A user level description of the problem or "" if it is valid.
*/
template <typename TYPE>
std::string WorkspaceProperty<TYPE>::isValidGroup(
boost::shared_ptr<WorkspaceGroup> wsGroup) const {
......@@ -395,9 +405,10 @@ std::string WorkspaceProperty<TYPE>::isValidGroup(
// Table Workspaces are ignored
if ("TableWorkspace" == memberWs->id()) {
error = "Workspace " + memberWsName + " is of type TableWorkspace and "
"will therefore be ignored as "
"part of the GroupedWorkspace.";
error = "Workspace " + memberWsName +
" is of type TableWorkspace and "
"will therefore be ignored as "
"part of the GroupedWorkspace.";
g_log.debug() << error << '\n';
} else {
......@@ -427,10 +438,10 @@ std::string WorkspaceProperty<TYPE>::isValidGroup(
}
/** Checks whether the entered output workspace is valid.
* To be valid the only thing it needs is a name that is allowed by the ADS,
* @see AnalysisDataServiceImpl
* @returns A user level description of the problem or "" if it is valid.
*/
* To be valid the only thing it needs is a name that is allowed by the ADS,
* @see AnalysisDataServiceImpl
* @returns A user level description of the problem or "" if it is valid.
*/
template <typename TYPE>
std::string WorkspaceProperty<TYPE>::isValidOutputWs() const {
std::string error;
......@@ -448,10 +459,10 @@ std::string WorkspaceProperty<TYPE>::isValidOutputWs() const {
}
/** Checks whether the entered workspace (that by this point we've found is
* not in the ADS)
* is actually an optional workspace and so still valid.
* @returns A user level description of the problem or "" if it is valid.
*/
* not in the ADS)
* is actually an optional workspace and so still valid.
* @returns A user level description of the problem or "" if it is valid.
*/
template <typename TYPE>
std::string WorkspaceProperty<TYPE>::isOptionalWs() const {
std::string error;
......@@ -477,8 +488,8 @@ template <typename TYPE> void WorkspaceProperty<TYPE>::clear() {
}
/** Attempts to retreive the data from the ADS
* if the data is not foung the internal pointer is set to null.
*/
* if the data is not foung the internal pointer is set to null.
*/
template <typename TYPE>
void WorkspaceProperty<TYPE>::retrieveWorkspaceFromADS() {
// Try and get the workspace from the ADS, but don't worry if we can't
......
......@@ -10,6 +10,8 @@
#include "MantidAPI/AlgorithmProperty.h"
#include "MantidAPI/Algorithm.h"
#include <json/value.h>
namespace Mantid {
namespace API {
......@@ -53,6 +55,13 @@ AlgorithmProperty &AlgorithmProperty::operator=(const AlgorithmProperty &rhs) {
*/
std::string AlgorithmProperty::value() const { return m_algStr; }
/**
* @return A Json::Value objectValue encoding the algorithm
*/
Json::Value AlgorithmProperty::valueAsJson() const {
return (*this)()->toJson();
}
/**
* Get the default
* @returns An empty string
......
......@@ -13,6 +13,7 @@
#include <Poco/ActiveMethod.h>
#include <Poco/ActiveResult.h>
#include <Poco/Void.h>
#include <json/value.h>
using namespace Mantid::Kernel;
......@@ -305,8 +306,16 @@ void AlgorithmProxy::setChildEndProgress(const double endProgress) const {
*/
std::string AlgorithmProxy::toString() const {
const_cast<AlgorithmProxy *>(this)->createConcreteAlg(true);
std::string serialized = m_alg->toString();
return serialized;
return m_alg->toString();
}
/**
* Serialize this object to a Json::Value. Simple routes the call the algorithm
* @returns This object serialized as a Json::Value
*/
Json::Value AlgorithmProxy::toJson() const {
const_cast<AlgorithmProxy *>(this)->createConcreteAlg(true);
return m_alg->toJson();
}
/// Function to return all of the categories that contain this algorithm
......
......@@ -8,6 +8,8 @@
#include "MantidAPI/FunctionFactory.h"
#include "MantidKernel/PropertyHistory.h"
#include <json/value.h>
namespace Mantid {
namespace API {
/** Constructor.
......@@ -62,6 +64,14 @@ std::string FunctionProperty::value() const {
return getDefault();
}
/**
* @return A Json::Value object encoding the string representation of the
* function
*/
Json::Value FunctionProperty::valueAsJson() const {
return Json::Value(value());
}
/** Get the value the property was initialised with -its default value
* @return The default value
*/
......
......@@ -14,6 +14,7 @@
#include "MantidAPI/Algorithm.h"
#include "MantidAPI/AlgorithmHasProperty.h"
#include "MantidAPI/AlgorithmProperty.h"
#include <json/value.h>
using namespace Mantid::API;
using namespace Mantid::Kernel;
......@@ -144,6 +145,19 @@ public:
adder->initialize();
TS_ASSERT_THROWS_NOTHING(testAlg.setProperty("CalculateStep", adder));
}
void test_ValueAsJson() {
AlgorithmProperty prop("name");
SimpleSum adder;
adder.initialize();
adder.execute();
prop.setValue(adder.toString());
const auto jsonValue = prop.valueAsJson();
TS_ASSERT_EQUALS(Json::objectValue, jsonValue.type());
TS_ASSERT_EQUALS(adder.name(), jsonValue["name"].asString());
TS_ASSERT_EQUALS(adder.version(), jsonValue["version"].asInt());
TS_ASSERT_EQUALS(3, jsonValue["properties"]["Output1"].asInt());
}
};
#endif /* MANTID_API_ALGORITHMPROPERTYTEST_H_ */
......@@ -366,7 +366,7 @@ public:
alg.setPropertyValue("prop1", "value1");
alg.setProperty("prop2", 5);
std::string expected = "{\"name\":\"ToyAlgorithm\",\"properties\":{"
"\"prop1\":\"value1\",\"prop2\":\"5\"},\"version\":"
"\"prop1\":\"value1\",\"prop2\":5},\"version\":"
"1}\n";
TS_ASSERT_EQUALS(alg.toString(), expected);
}
......
......@@ -13,6 +13,7 @@
#include "MantidAPI/FunctionProperty.h"
#include "MantidAPI/ParamFunction.h"
#include <boost/shared_ptr.hpp>
#include <json/value.h>
using namespace Mantid::Kernel;
using namespace Mantid::API;
......@@ -60,6 +61,13 @@ public:
"name=FunctionPropertyTest_Function,A=3,B=2");
}
void testValueAsJson() {
FunctionProperty prop("fun");
const std::string funcString("name=FunctionPropertyTest_Function,A=3,B=2");
prop.setValue(funcString);
TS_ASSERT_EQUALS(funcString, prop.valueAsJson().asString());
}
void testBadValue() {
FunctionProperty prop("fun");
std::string error;
......
......@@ -13,6 +13,7 @@
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidTestHelpers/FakeObjects.h"
#include <boost/shared_ptr.hpp>
#include <json/value.h>
// Property implementations
#include "MantidAPI/WorkspaceProperty.tcc"
......@@ -86,6 +87,12 @@ public:
TS_ASSERT_EQUALS(wsp3->value(), "ws3")
}
void testValueAsJson() {
TS_ASSERT_EQUALS("ws1", wsp1->valueAsJson().asString());
TS_ASSERT_EQUALS("", wsp2->valueAsJson().asString());
TS_ASSERT_EQUALS("ws3", wsp3->valueAsJson().asString());
}
void testIsValueSerializable() {
WorkspaceProperty<Workspace> p("PropertyName", "", Direction::InOut);
TS_ASSERT(p.isValueSerializable());
......
......@@ -90,7 +90,7 @@ set ( SRC_FILES
src/PropertyManagerProperty.cpp
src/PropertyNexus.cpp
src/PropertyWithValue.cpp
src/PropertyWithValueJSONDecoder.cpp
src/PropertyWithValueJSON.cpp
src/ProxyInfo.cpp
src/PseudoRandomNumberGenerator.cpp
src/Quat.cpp
......@@ -261,7 +261,7 @@ set ( INC_FILES
inc/MantidKernel/PropertyManager_fwd.h
inc/MantidKernel/PropertyNexus.h
inc/MantidKernel/PropertyWithValue.h
inc/MantidKernel/PropertyWithValueJSONDecoder
inc/MantidKernel/PropertyWithValueJSON.h
inc/MantidKernel/ProxyInfo.h
inc/MantidKernel/PseudoRandomNumberGenerator.h
inc/MantidKernel/QuasiRandomNumberSequence.h
......@@ -412,7 +412,7 @@ set ( TEST_FILES
PropertyNexusTest.h
PropertyTest.h
PropertyWithValueTest.h
PropertyWithValueJSONDecoderTest.h
PropertyWithValueJSONTest.h
ProxyInfoTest.h
QuatTest.h
ReadLockTest.h
......
......@@ -12,6 +12,10 @@
#include <map>
#include <string>
namespace Json {
class Value;
}
namespace Mantid {
namespace Kernel {
......@@ -20,6 +24,13 @@ namespace Kernel {
class MANTID_KERNEL_DLL OptionalBool {
public:
enum Value { Unset, True, False };
static std::map<std::string, Value> strToEmumMap();
static std::map<Value, std::string> enumToStrMap();
const static std::string StrUnset;
const static std::string StrFalse;
const static std::string StrTrue;
public:
OptionalBool();
OptionalBool(bool arg);
OptionalBool(Value arg);
......@@ -27,12 +38,6 @@ public:
bool operator==(const OptionalBool &other) const;
Value getValue() const;
static std::map<std::string, Value> strToEmumMap();
static std::map<Value, std::string> enumToStrMap();
const static std::string StrUnset;
const static std::string StrFalse;
const static std::string StrTrue;
private:
friend MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &os,
OptionalBool const &object);
......@@ -48,6 +53,9 @@ MANTID_KERNEL_DLL std::ostream &operator<<(std::ostream &os,
MANTID_KERNEL_DLL std::istream &operator>>(std::istream &istream,
OptionalBool &object);
/// Encode an OptionalBool as a Json::Value.
MANTID_KERNEL_DLL ::Json::Value encodeAsJson(const OptionalBool &);
} // namespace Kernel
} // namespace Mantid
......
......@@ -15,14 +15,17 @@
#include <boost/shared_ptr.hpp>
#endif
namespace NeXus {
class File;
}
#include <set>
#include <string>
#include <vector>
namespace NeXus {
class File;
}
namespace Json {
class Value;
}
namespace std {
class typeinfo;
}
......@@ -133,6 +136,8 @@ public:
/// Returns the value of the property as a pretty printed string
virtual std::string valueAsPrettyStr(const size_t maxLength = 0,
const bool collapseLists = true) const;
/// Returns the value of the property as a Json::Value
virtual Json::Value valueAsJson() const = 0;
/// Whether the string returned by value() can be used for serialization.
virtual bool isValueSerializable() const { return true; }
/// Set the value of the property via a string. If the value is unacceptable
......
......@@ -58,6 +58,7 @@ public:
// Function to declare properties (i.e. store them)
void declareProperty(std::unique_ptr<Property> p,
const std::string &doc = "") override;
using IPropertyManager::declareProperty;
void declareOrReplaceProperty(std::unique_ptr<Property> p,
const std::string &doc = "") override;
......@@ -107,8 +108,6 @@ public:
::Json::Value asJson(bool withDefaultValues = false) const override;
protected:
using IPropertyManager::declareProperty;
friend class PropertyManagerOwner;
Property *getPointerToProperty(const std::string &name) const override;
......@@ -134,6 +133,9 @@ private:
/// Typedef for a shared pointer to a PropertyManager
using PropertyManager_sptr = boost::shared_ptr<PropertyManager>;
/// Return the value of the PropertyManager as a Json::Value
MANTID_KERNEL_DLL ::Json::Value encodeAsJson(const PropertyManager &propMgr);
} // namespace Kernel
} // namespace Mantid
......