gschjetne / json-mop Goto Github PK
View Code? Open in Web Editor NEWA metaclass for bridging CLOS and JSON objects
License: MIT License
A metaclass for bridging CLOS and JSON objects
License: MIT License
Using :json-type (:hash-table object) is not supported.
It is quite useful to specify required slots.
Therefore we can add an required
slot to the json-serializable-slot
class.
Then in the initialize-slots-from-json
function it will be checked for each required slot.
I'm however not sure if there should be a warning or an error when a required slot is not present? @gschjetne
Once a class has been redefined, encode
throws a no applicable method error when you attempt to encode an instance.
I've made two extra test cases for this for tests/encode-decode.lisp
:
(test reload-encode ()
(load (asdf:system-relative-pathname :json-mop-tests "tests.lisp"))
(let ((child (make-instance 'child))
(parent-only (make-instance 'parent)))
(is (string= (with-output-to-string (s) (encode child s))
(with-output-to-string (s) (encode parent-only s))))))
(test reload-decode ()
(load (asdf:system-relative-pathname :json-mop-tests "tests.lisp"))
(let* ((child (make-instance 'child :foo "hello" :bar "quux"))
(child-rt (obj-rt child)))
(is (string= (foo child) (foo child-rt)))
(is (string= (bar child) (bar child-rt)))))
Failure Details:
--------------------------------
RELOAD-DECODE []:
Unexpected Error: #<SB-PCL::NO-APPLICABLE-METHOD-ERROR {10064BF7A3}>
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION YASON:ENCODE (15)>
when called with arguments
(#<CHILD {10064BF5D3}> #<SB-IMPL::STRING-OUTPUT-STREAM {CA0E523}>).
See also:
The ANSI Standard, Section 7.6.6.
--------------------------------
--------------------------------
RELOAD-ENCODE []:
Unexpected Error: #<SB-PCL::NO-APPLICABLE-METHOD-ERROR {1005F5BDA3}>
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION YASON:ENCODE (15)>
when called with arguments
(#<CHILD {1005EC97A3}> #<SB-IMPL::STRING-OUTPUT-STREAM {CA0E583}>).
See also:
The ANSI Standard, Section 7.6.6.
--------------------------------
JSON maps (hash-tables) with strings as keys and objects as values can not be consumed so far.
A function for that would be useful. I was not sure how to name it best tough...
(defmethod json-object-to-clos ((input hash-table) class &rest initargs)
(let ((hash-table
(make-hash-table :test #'equal :size (hash-table-size input))))
(loop for key being the hash-keys of input
for value being the hash-values of input
do (setf (gethash key hash-table)
(apply #'json-to-clos value class initargs)))
hash-table))
The method also needs to be specialized on stream
, pathname
, etc. as done with json-to-clos
.
Encoding these hash-table
of objects will be more difficult and might be implemented like homogeneous-sequence-intermediate-class
.
Here is an example using book
class from the readme:
(json-object-to-clos
(yason:parse "{
\"first-book\": {
\"title\": \"The Gilded Age: A Tale of Today\",
\"year_published\": 1873
},
\"second-book\": {
\"title\": \"The Gilded Age: A Tale of Today\",
\"year_published\": 1873
}
}")
'book)
This is useful for many things, like automatically generating a CLOS hierarchy from a schema to consume, or generating a schema for other applications to use when consuming JSON produced by this library.
JSON-MOP> (defclass test-class () () (:metaclass json-serializable-class))
#<JSON-SERIALIZABLE-CLASS JSON-MOP::TEST-CLASS>
JSON-MOP> (typep (make-instance 'test-class) 'json-serializable)
T ;; just as expected
JSON-MOP> (defclass test-class () () (:metaclass json-serializable-class))
#<JSON-SERIALIZABLE-CLASS JSON-MOP::TEST-CLASS>
JSON-MOP> (typep (make-instance 'test-class) 'json-serializable)
NIL ;; wat
This is because appending the json-serializable
class in
Lines 52 to 58 in e87e2d5
only happens in initialize-instance
and not reinitialize-instance
.
Hi. I'm kind of a CL newbie, but I'm trying to use json-mop and having an issue with inheritance.
Suppose I have two classes:
(defclass parent ()
((foo :accessor foo :initarg :foo
:initform "Foo"
:json-key "foo"))
(:metaclass json-serializable-class))
(defclass child (parent)
((bar :accessor bar :initarg :bar
:json-key "bar"))
(:metaclass json-serializable-class))
(encode (make-instance 'parent))
prints exactly what I expect: {"foo":"Foo"}
I would expect (encode (make-instance 'child))
to print exactly the same thing. However, it prints
{}
.
But:
(describe (make-instance 'child))
#<CHILD {1004ABEC93}>
[standard-object]
Slots with :INSTANCE allocation:
FOO = "Foo"
BAR = #<unbound slot>
Maybe I'm misunderstanding a basic CLOS thing? Shouldn't encoding an instance of child
include the values it gets from parent
's initforms?
This seems to be the gold standard for JSON processing in Common Lisp these days.
It also has the advantage of having a stream oriented parser, which saves the inefficiency of consing a whole hash table for every CLOS object. With jzon we can create the objects and populate the slots directly.
I can succesfully consume a class person
from the according json format, but how do I invoke json-to-clos if my json endpoint returns a list of person
. Being fairly new to Common Lisp I do not grokk yet how to provide the according class information.
Hello, new to CL and this library. I am running into a strange error. Using :json-type :any seems to work for all types except when the object is a hash-table. Has anyone else had this issue or am I missing something?
There is no class named :ANY.
[Condition of type SB-PCL:CLASS-NOT-FOUND-ERROR]
Restarts:
0: [*ABORT] Return to SLIME's top level.
1: [ABORT] abort thread (#<THREAD "worker" RUNNING {10024BCBD3}>)
Backtrace:
0: (SB-PCL::FIND-CLASS-FROM-CELL :ANY NIL T)
Locals:
CELL = NIL
ERRORP = T
SYMBOL = :ANY
1: ((:METHOD MAKE-INSTANCE (SYMBOL)) :ANY) [fast-method]
Locals:
CLASS = :ANY
SB-DEBUG::MORE = NIL
2: ((:METHOD JSON-TO-CLOS (HASH-TABLE T)) #<HASH-TABLE :TEST EQUAL :COUNT 2 {10025E8173}> :ANY) [fast-method]
Locals:
CLASS = :ANY
JSON-MOP::INPUT = #<HASH-TABLE :TEST EQUAL :COUNT 2 {10025E8173}>
SB-DEBUG::MORE = NIL
3: ((:METHOD JSON-TO-CLOS (HASH-TABLE T)) #<HASH-TABLE :TEST EQUAL :COUNT 17 {10025E4BF3}> OBJECT) [fast-method]
Locals:
CLASS = OBJECT
JSON-MOP::INPUT = #<HASH-TABLE :TEST EQUAL :COUNT 17 {10025E4BF3}>
JSON-MOP::KEY-COUNT = 11
JSON-MOP::LISP-OBJECT = #<OBJECT {10025E9D73}>
SB-DEBUG::MORE = NIL
Thank you for any help, great library over all and very useful.
For some reason the pipeline hangs for hours, perhaps indefinitely on the Roswell install step for Clozure Common Lisp. We should find out why and get it working again.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.