diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
index f2d76a501ecf8e1f53dcf9bf80a2e8a0f66d7536..8a2856b2516784d6d5c0413a5123af9665696d22 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
@@ -19,16 +19,7 @@ namespace armarx
     {
         if (nameOrID.find("/") != nameOrID.npos)
         {
-            const std::vector<std::string> split = simox::alg::split(nameOrID, "/", true);
-            ARMARX_CHECK(split.size() == 2 || split.size() == 3)
-                    << "Expected ID of format 'Dataset/ClassName' or 'Dataset/ClassName/InstanceName'"
-                    << ", but got: '" << nameOrID << "' (too many '/').";
-            _dataset = split[0];
-            _className = split[1];
-            if (split.size() == 3)
-            {
-                _instanceName = split[2];
-            }
+            setFromString(nameOrID);
         }
         else
         {
@@ -37,6 +28,30 @@ namespace armarx
         }
     }
 
+    ObjectID ObjectID::FromString(const std::string& idString)
+    {
+        ObjectID id;
+        id.setFromString(idString);
+        return id;
+    }
+
+    void ObjectID::setFromString(const std::string& idString)
+    {
+        const std::vector<std::string> split = simox::alg::split(idString, "/", true);
+        ARMARX_CHECK(split.size() == 2 || split.size() == 3)
+                << "Expected ID of format 'Dataset/ClassName' or 'Dataset/ClassName/InstanceName'"
+                << ", but got: '" << idString << "' "
+                << "(expected 2 or 3 '/'s, but found " << split.size() << ").";
+
+        _dataset = split[0];
+        _className = split[1];
+
+        if (split.size() == 3)
+        {
+            _instanceName = split[2];
+        }
+    }
+
     std::string ObjectID::str() const
     {
         std::string _str = _dataset + "/" + _className;
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
index 389b203a6ecc67f2f6cd074ce103c5b52687a2be..b152844b17f150b80c44f8ed3c849e263b2e8fd4 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
@@ -17,6 +17,9 @@ namespace armarx
         /// Construct from either a class name ("myobject") or ID ("mydataset/myobject", "mydataset/myclass/myinstance").
         ObjectID(const std::string& nameOrID);
 
+        /// Construct from a string produced by `str()`, e.g. ("mydataset/myobject", "mydataset/myclass/myinstance").
+        static ObjectID FromString(const std::string& idString);
+
 
         inline std::string dataset() const
         {
@@ -37,6 +40,8 @@ namespace armarx
 
         /// Return "dataset/className" or "dataset/className/instanceName".
         std::string str() const;
+        void setFromString(const std::string& idString);
+
 
         /// Return just the class ID without an intance name.
         ObjectID getClassID() const;
diff --git a/source/RobotAPI/libraries/ArmarXObjects/test/ObjectIDTest.cpp b/source/RobotAPI/libraries/ArmarXObjects/test/ObjectIDTest.cpp
index d14a0d60406cd4074a6ab67d79885ad9041b5914..7063ef69b2490bdea0ba91d76a2a19da6c96e057 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/test/ObjectIDTest.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/test/ObjectIDTest.cpp
@@ -36,21 +36,46 @@ namespace armarx
 {
     struct Fixture
     {
-        std::vector<armarx::ObjectID> dcs
+        std::vector<armarx::ObjectID> dcsStringConstructor
         {
             { "Data/Class/0" },
             { "Data/Class/1" },
             { "Data/Class/2" }
         };
-        armarx::ObjectID dc0 { "Data/Class/0" };
+        std::vector<armarx::ObjectID> dcsFromString
+        {
+            ObjectID::FromString("Data/Class/0"),
+            ObjectID::FromString("Data/Class/1"),
+            ObjectID::FromString("Data/Class/2")
+        };
+        std::vector<std::vector<armarx::ObjectID>*> dcs {
+            &dcsStringConstructor,
+            &dcsFromString
+        };
+
+        armarx::ObjectID dc0StringConstructor { "Data/Class/0" };
+        armarx::ObjectID dc0FromString = ObjectID::FromString("Data/Class/0");
+        std::vector<armarx::ObjectID*> dc0s {
+            &dc0StringConstructor,
+            &dc0FromString,
+        };
 
-        std::vector<armarx::ObjectID> ots
+        std::vector<armarx::ObjectID> otsStringConstructor
         {
             { "Other/Type/0" },
             { "Other/Type/1" },
             { "Other/Type/2" }
         };
-        armarx::ObjectID ot0 { "Other/Type/0" };
+        std::vector<armarx::ObjectID> otsFromString
+        {
+            ObjectID::FromString("Other/Type/0"),
+            ObjectID::FromString("Other/Type/1"),
+            ObjectID::FromString("Other/Type/2")
+        };
+        std::vector<std::vector<armarx::ObjectID>*> ots {
+            &otsStringConstructor,
+            &otsFromString
+        };
     };
 }
 
@@ -58,29 +83,44 @@ BOOST_FIXTURE_TEST_SUITE(ObjectIDTests, armarx::Fixture)
 
 BOOST_AUTO_TEST_CASE(test_construction_from_string)
 {
-    for (std::size_t i = 0; i < dcs.size(); ++i)
+    for (const auto* dc : dcs)
     {
-        BOOST_CHECK_EQUAL(dcs[i].dataset(), "Data");
-        BOOST_CHECK_EQUAL(dcs[i].className(), "Class");
-        BOOST_CHECK_EQUAL(dcs[i].instanceName(), std::to_string(i));
+        for (const auto* ot : ots)
+        {
+            for (std::size_t i = 0; i < dc->size(); ++i)
+            {
+                BOOST_CHECK_EQUAL((*dc)[i].dataset(), "Data");
+                BOOST_CHECK_EQUAL((*dc)[i].className(), "Class");
+                BOOST_CHECK_EQUAL((*dc)[i].instanceName(), std::to_string(i));
 
-        BOOST_CHECK_EQUAL(ots[i].dataset(), "Other");
-        BOOST_CHECK_EQUAL(ots[i].className(), "Type");
-        BOOST_CHECK_EQUAL(ots[i].instanceName(), std::to_string(i));
+                BOOST_CHECK_EQUAL((*ot)[i].dataset(), "Other");
+                BOOST_CHECK_EQUAL((*ot)[i].className(), "Type");
+                BOOST_CHECK_EQUAL((*ot)[i].instanceName(), std::to_string(i));
+            }
+        }
     }
 }
 
 BOOST_AUTO_TEST_CASE(test_equals_operator)
 {
-    for (std::size_t i = 0; i < dcs.size(); ++i)
+    for (const auto* dc : dcs)
     {
-        BOOST_TEST_CONTEXT("i=" << i)
+        for (const auto* ot : ots)
         {
-            BOOST_CHECK_EQUAL(dcs[i], dcs[i]);
-            BOOST_CHECK_NE(dcs[i], ots[i]);
-            if (i != 0)
+            for (const auto* dc0 : dc0s)
             {
-                BOOST_CHECK_NE(dcs[i], dc0);
+                for (std::size_t i = 0; i < (*dc).size(); ++i)
+                {
+                    BOOST_TEST_CONTEXT("i=" << i)
+                    {
+                        BOOST_CHECK_EQUAL((*dc)[i], (*dc)[i]);
+                        BOOST_CHECK_NE((*dc)[i], (*ot)[i]);
+                        if (i != 0)
+                        {
+                            BOOST_CHECK_NE((*dc)[i], *dc0);
+                        }
+                    }
+                }
             }
         }
     }
@@ -88,16 +128,19 @@ BOOST_AUTO_TEST_CASE(test_equals_operator)
 
 BOOST_AUTO_TEST_CASE(test_less_than_operator)
 {
-    for (std::size_t i = 0; i < dcs.size(); ++i)
+    for (const auto* dc : dcs)
     {
-        for (std::size_t j = i; j < dcs.size(); ++j)
+        for (std::size_t i = 0; i < (*dc).size(); ++i)
         {
-            BOOST_CHECK_LE(dcs[i], dcs[j]);
-            BOOST_CHECK_GE(dcs[j], dcs[i]);
-            if (i != j)
+            for (std::size_t j = i; j < (*dc).size(); ++j)
             {
-                BOOST_CHECK_LT(dcs[i], dcs[j]);
-                BOOST_CHECK_GT(dcs[j], dcs[i]);
+                BOOST_CHECK_LE((*dc)[i], (*dc)[j]);
+                BOOST_CHECK_GE((*dc)[j], (*dc)[i]);
+                if (i != j)
+                {
+                    BOOST_CHECK_LT((*dc)[i], (*dc)[j]);
+                    BOOST_CHECK_GT((*dc)[j], (*dc)[i]);
+                }
             }
         }
     }
@@ -105,15 +148,21 @@ BOOST_AUTO_TEST_CASE(test_less_than_operator)
 
 BOOST_AUTO_TEST_CASE(test_equalClass)
 {
-    for (std::size_t i = 0; i < dcs.size(); ++i)
+    for (const auto* dc : dcs)
     {
-        for (std::size_t j = 0; j < dcs.size(); ++j)
+        for (const auto* ot : ots)
         {
-            BOOST_CHECK(dcs[i].equalClass(dcs[j]));
-            BOOST_CHECK(ots[i].equalClass(ots[j]));
-
-            BOOST_CHECK(!dcs[i].equalClass(ots[j]));
-            BOOST_CHECK(!ots[i].equalClass(dcs[j]));
+            for (std::size_t i = 0; i < (*dc).size(); ++i)
+            {
+                for (std::size_t j = 0; j < (*dc).size(); ++j)
+                {
+                    BOOST_CHECK((*dc)[i].equalClass((*dc)[j]));
+                    BOOST_CHECK((*ot)[i].equalClass((*ot)[j]));
+
+                    BOOST_CHECK(!(*dc)[i].equalClass((*ot)[j]));
+                    BOOST_CHECK(!(*ot)[i].equalClass((*dc)[j]));
+                }
+            }
         }
     }
 }