diff --git a/wsme/rest/json.py b/wsme/rest/json.py
index 07388bb..abe3d4a 100644
--- a/wsme/rest/json.py
+++ b/wsme/rest/json.py
@@ -27,6 +27,8 @@ accept_content_types = [
     'text/javascript',
     'application/javascript'
 ]
+ENUM_TRUE = ('true', 't', 'yes', 'y', 'on', '1')
+ENUM_FALSE = ('false', 'f', 'no', 'n', 'off', '0')
 
 
 @generic
@@ -182,6 +184,28 @@ def text_fromjson(datatype, value):
     return value
 
 
+@fromjson.when_object(*six.integer_types + (float,))
+def numeric_fromjson(datatype, value):
+    """Convert string object to built-in types int, long or float."""
+    if value is None:
+        return None
+    return datatype(value)
+
+
+@fromjson.when_object(bool)
+def bool_fromjson(datatype, value):
+    """Convert to bool, restricting strings to just unambiguous values."""
+    if value is None:
+        return None
+    if isinstance(value, six.integer_types + (bool,)):
+        return bool(value)
+    if value in ENUM_TRUE:
+        return True
+    if value in ENUM_FALSE:
+        return False
+    raise ValueError("Value not an unambiguous boolean: %s" % value)
+
+
 @fromjson.when_object(decimal.Decimal)
 def decimal_fromjson(datatype, value):
     if value is None:
diff --git a/wsme/tests/protocol.py b/wsme/tests/protocol.py
index 35a744d..b70f02d 100644
--- a/wsme/tests/protocol.py
+++ b/wsme/tests/protocol.py
@@ -65,6 +65,11 @@ class NamedAttrsObject(object):
     attr_2 = wsme.types.wsattr(int, name='attr.2')
 
 
+class CustomObject(object):
+    aint = int
+    name = wsme.types.text
+
+
 class NestedInnerApi(object):
     @expose(bool)
     def deepfunction(self):
@@ -166,6 +171,10 @@ class ArgTypes(object):
         if not (a == b):
             raise AssertionError('%s != %s' % (a, b))
 
+    def assertIsInstance(self, value, v_type):
+        assert isinstance(value, v_type), ("%s is not instance of type %s" %
+                                           (value, v_type))
+
     @expose(wsme.types.bytes)
     @validate(wsme.types.bytes)
     def setbytes(self, value):
@@ -307,6 +316,14 @@ class ArgTypes(object):
         self.assertEquals(value.attr_2, 20)
         return value
 
+    @expose(CustomObject)
+    @validate(CustomObject)
+    def setcustomobject(self, value):
+        self.assertIsInstance(value, CustomObject)
+        self.assertIsInstance(value.name, wsme.types.text)
+        self.assertIsInstance(value.aint, int)
+        return value
+
 
 class BodyTypes(object):
     def assertEquals(self, a, b):
diff --git a/wsme/tests/test_restjson.py b/wsme/tests/test_restjson.py
index 6297b59..08af1c0 100644
--- a/wsme/tests/test_restjson.py
+++ b/wsme/tests/test_restjson.py
@@ -13,7 +13,7 @@ from wsme.rest.json import fromjson, tojson, parse
 from wsme.utils import parse_isodatetime, parse_isotime, parse_isodate
 from wsme.types import isarray, isdict, isusertype, register_type
 from wsme.rest import expose, validate
-from wsme.exc import InvalidInput
+from wsme.exc import ClientSideError, InvalidInput
 
 
 import six
@@ -270,6 +270,15 @@ class TestRestJson(wsme.tests.protocol.RestOnlyProtocolTestCase):
             "Unknown argument:"
         )
 
+    def test_set_custom_object(self):
+        r = self.app.post(
+            '/argtypes/setcustomobject',
+            '{"value": {"aint": 2, "name": "test"}}',
+            headers={"Content-Type": "application/json"}
+        )
+        self.assertEqual(r.status_int, 200)
+        self.assertEqual(r.json, {'aint': 2, 'name': 'test'})
+
     def test_unset_attrs(self):
         class AType(object):
             attr = int
@@ -328,6 +337,107 @@ class TestRestJson(wsme.tests.protocol.RestOnlyProtocolTestCase):
             assert e.value == jdate
             assert e.msg == "'%s' is not a legal date value" % jdate
 
+    def test_valid_str_to_builtin_fromjson(self):
+        types = six.integer_types + (bool, float)
+        value = '2'
+        for t in types:
+            for ba in True, False:
+                jd = '%s' if ba else '{"a": %s}'
+                i = parse(jd % value, {'a': t}, ba)
+                self.assertEqual(
+                    i, {'a': t(value)},
+                    "Parsed value does not correspond for %s: "
+                    "%s != {'a': %s}" % (
+                        t, repr(i), repr(t(value))
+                    )
+                )
+                self.assertIsInstance(i['a'], t)
+
+    def test_valid_int_fromjson(self):
+        value = 2
+        for ba in True, False:
+            jd = '%d' if ba else '{"a": %d}'
+            i = parse(jd % value, {'a': int}, ba)
+            self.assertEqual(i, {'a': 2})
+            self.assertIsInstance(i['a'], int)
+
+    def test_valid_num_to_float_fromjson(self):
+        values = 2, 2.3
+        for v in values:
+            for ba in True, False:
+                jd = '%f' if ba else '{"a": %f}'
+                i = parse(jd % v, {'a': float}, ba)
+                self.assertEqual(i, {'a': float(v)})
+                self.assertIsInstance(i['a'], float)
+
+    def test_invalid_str_to_buitin_fromjson(self):
+        types = six.integer_types + (float, bool)
+        value = '2a'
+        for t in types:
+            for ba in True, False:
+                jd = '"%s"' if ba else '{"a": "%s"}'
+                try:
+                    parse(jd % value, {'a': t}, ba)
+                    assert False, (
+                        "Value '%s' should not parse correctly for %s." %
+                        (value, t)
+                    )
+                except ClientSideError as e:
+                    self.assertIsInstance(e, InvalidInput)
+                    self.assertEqual(e.fieldname, 'a')
+                    self.assertEqual(e.value, value)
+
+    def test_ambiguous_to_bool(self):
+        amb_values = ('', 'randomstring', '2', '-32', 'not true')
+        for value in amb_values:
+            for ba in True, False:
+                jd = '"%s"' if ba else '{"a": "%s"}'
+                try:
+                    parse(jd % value, {'a': bool}, ba)
+                    assert False, (
+                        "Value '%s' should not parse correctly for %s." %
+                        (value, bool)
+                    )
+                except ClientSideError as e:
+                    self.assertIsInstance(e, InvalidInput)
+                    self.assertEqual(e.fieldname, 'a')
+                    self.assertEqual(e.value, value)
+
+    def test_true_strings_to_bool(self):
+        true_values = ('true', 't', 'yes', 'y', 'on', '1')
+        for value in true_values:
+            for ba in True, False:
+                jd = '"%s"' if ba else '{"a": "%s"}'
+                i = parse(jd % value, {'a': bool}, ba)
+                self.assertIsInstance(i['a'], bool)
+                self.assertTrue(i['a'])
+
+    def test_false_strings_to_bool(self):
+        false_values = ('false', 'f', 'no', 'n', 'off', '0')
+        for value in false_values:
+            for ba in True, False:
+                jd = '"%s"' if ba else '{"a": "%s"}'
+                i = parse(jd % value, {'a': bool}, ba)
+                self.assertIsInstance(i['a'], bool)
+                self.assertFalse(i['a'])
+
+    def test_true_ints_to_bool(self):
+        true_values = (1, 5, -3)
+        for value in true_values:
+            for ba in True, False:
+                jd = '%d' if ba else '{"a": %d}'
+                i = parse(jd % value, {'a': bool}, ba)
+                self.assertIsInstance(i['a'], bool)
+                self.assertTrue(i['a'])
+
+    def test_false_ints_to_bool(self):
+        value = 0
+        for ba in True, False:
+            jd = '%d' if ba else '{"a": %d}'
+            i = parse(jd % value, {'a': bool}, ba)
+            self.assertIsInstance(i['a'], bool)
+            self.assertFalse(i['a'])
+
     def test_nest_result(self):
         self.root.protocols[0].nest_result = True
         r = self.app.get('/returntypes/getint.json')
diff --git a/wsme/tests/test_spore.py b/wsme/tests/test_spore.py
index 03b0228..60afdc9 100644
--- a/wsme/tests/test_spore.py
+++ b/wsme/tests/test_spore.py
@@ -18,7 +18,7 @@ class TestSpore(unittest.TestCase):
 
         spore = json.loads(spore)
 
-        assert len(spore['methods']) == 49, str(len(spore['methods']))
+        assert len(spore['methods']) == 50, str(len(spore['methods']))
 
         m = spore['methods']['argtypes_setbytesarray']
         assert m['path'] == 'argtypes/setbytesarray', m['path']
diff --git a/wsmeext/tests/test_soap.py b/wsmeext/tests/test_soap.py
index 3e070a7..9fdfebc 100644
--- a/wsmeext/tests/test_soap.py
+++ b/wsmeext/tests/test_soap.py
@@ -397,7 +397,7 @@ class TestSOAP(wsme.tests.protocol.ProtocolTestCase):
 
         assert len(sd.ports) == 1
         port, methods = sd.ports[0]
-        self.assertEquals(len(methods), 49)
+        self.assertEquals(len(methods), 50)
 
         methods = dict(methods)