Причина ошибки заключается в том, что cl-json:*json-symbols-package*
связан с пакетом KEYWORD
: когда ключи JSON превращаются в символы, они становятся ключевыми словами, которые, очевидно, недопустимы в качестве имен слотов.
Жидкие объекты
Следующие работы:
(let ((json:*json-symbols-package* (find-package :cl-user)))
(json:with-decoder-simple-clos-semantics
(json:decode-json-from-string "{ \"bar\" : 3 }")))
(примечание: перед двойными кавычками нужны только обратные слэши)
Вы получаете FLUID-OBJECT
.
Ключ прототипа в данных JSON
Теперь вы также можете определить свой собственный класс:
(in-package :cl-user)
(defclass foo ()
((bar :initarg :bar)))
И затем JSON должен иметь ключ "prototype"
:
(let ((json:*json-symbols-package* (find-package :cl-user)))
(json:with-decoder-simple-clos-semantics
(json:decode-json-from-string
"{ \"bar\" : 3 ,
\"prototype\" : { \"lispClass\" : \"foo\",
\"lispPackage\" : \"cl-user\" }}")))
Вышеприведенное возвращает экземпляр FOO
.
Вы можете использовать ключ, отличный от "prototype"
, связав *prototype-name*
.
Принудительный прототип по умолчанию (хак)
Не изменяя существующий код библиотеки, вы можете взломать его, чтобы изменить поведение шага декодирования. Код организован вокруг специальных переменных, которые используются в качестве обратных вызовов в различных точках синтаксического анализа, поэтому необходимо обернуть ожидаемую функцию своей собственной:
(defun wrap-for-class (class &optional (fn json::*end-of-object-handler*))
(let ((prototype (make-instance 'json::prototype :lisp-class class)))
(lambda ()
;; dynamically rebind *prototype* right around calling fn
(let ((json::*prototype* prototype))
(funcall fn)))))
Вышеприведенное создает объект-прототип для данного класса (символа), захватывает текущую привязку *end-of-object-handler*
и возвращает замыкание, которое при вызове привязывает *prototype*
к закрытому экземпляру прототипа.
Затем вы называете это следующим образом:
(let ((json:*json-symbols-package* *package*))
(json:with-decoder-simple-clos-semantics
(let ((json::*end-of-object-handler* (wrap-for-class 'foo)))
(json:decode-json-from-string
"{ \"bar\" : 3 }"))))
И у вас есть экземпляр FOO
.