├── .gitignore ├── test ├── autotest │ └── test_suite │ │ ├── data │ │ ├── fail29.json │ │ ├── fail30.json │ │ ├── fail31.json │ │ ├── fail16.json │ │ ├── fail33.json │ │ ├── fail2.json │ │ ├── fail24.json │ │ ├── fail4.json │ │ ├── fail8.json │ │ ├── fail19.json │ │ ├── fail23.json │ │ ├── fail27.json │ │ ├── fail28.json │ │ ├── fail9.json │ │ ├── fail20.json │ │ ├── fail5.json │ │ ├── fail6.json │ │ ├── fail7.json │ │ ├── fail11.json │ │ ├── fail12.json │ │ ├── fail14.json │ │ ├── fail21.json │ │ ├── fail25.json │ │ ├── fail15.json │ │ ├── fail17.json │ │ ├── fail22.json │ │ ├── fail3.json │ │ ├── fail26.json │ │ ├── fail32.json │ │ ├── fail13.json │ │ ├── fail18.json │ │ ├── pass2.json │ │ ├── fail1.json │ │ ├── fail10.json │ │ ├── pass3.json │ │ └── pass1.json │ │ ├── json_menu_example.txt │ │ ├── application.e │ │ ├── test_suite-safe.ecf │ │ ├── serialization │ │ ├── model │ │ │ ├── entity.e │ │ │ ├── person_details.e │ │ │ ├── person.e │ │ │ └── team.e │ │ ├── custom │ │ │ ├── team_json_serialization.e │ │ │ ├── person_json_serialization.e │ │ │ ├── person_details_json_serializer.e │ │ │ ├── person_json_serializer.e │ │ │ ├── team_json_deserializer.e │ │ │ ├── person_json_deserializer.e │ │ │ └── team_json_serializer.e │ │ └── test_json_serializer_with_reference.e │ │ ├── obsolete │ │ ├── converter │ │ │ ├── model │ │ │ │ ├── author.e │ │ │ │ ├── book.e │ │ │ │ └── book_collection.e │ │ │ ├── json_author_converter.e │ │ │ ├── json_book_converter.e │ │ │ ├── test_json_custom_classes.e │ │ │ └── json_book_collection_converter.e │ │ ├── test_obsolete_json.e │ │ └── test_ds.e │ │ ├── test_suite.ecf │ │ ├── test_obsolete_json.e │ │ └── test_ds.e └── run_autotest.bat ├── examples ├── basic │ ├── basic.rc │ ├── basic.ecf │ └── basic.e ├── serialization │ ├── serialization-safe.ecf │ ├── model │ │ ├── entity.e │ │ ├── team.e │ │ ├── person_details.e │ │ └── person.e │ ├── custom │ │ ├── team_json_serialization.e │ │ ├── person_json_serialization.e │ │ ├── person_details_json_serializer.e │ │ ├── team_json_deserializer.e │ │ ├── team_json_serializer.e │ │ ├── person_json_serializer.e │ │ └── person_json_deserializer.e │ ├── serialization.ecf │ ├── output_utilities.e │ ├── demo_basic_serialization.e │ ├── demo_custom_serialization.e │ └── application_serialization.e └── performance │ ├── basic.ecf │ └── basic.e ├── library ├── license.lic ├── parser │ ├── json_parser_access.e │ ├── json_tokens.e │ └── json_reader.e ├── json-safe.ecf ├── serialization │ ├── deserializer │ │ ├── support │ │ │ ├── linked_list_json_deserializer.e │ │ │ ├── arrayed_list_json_deserializer.e │ │ │ ├── list_json_deserializer.e │ │ │ ├── table_json_deserializer.e │ │ │ └── array_json_deserializer.e │ │ ├── creation │ │ │ ├── json_deserializer_creation_callback.e │ │ │ ├── json_deserializer_creation_agent_callback.e │ │ │ └── json_deserializer_creation_information.e │ │ ├── json_deserializer.e │ │ ├── basic │ │ │ ├── json_basic_deserializer.e │ │ │ └── json_basic_serialization.e │ │ ├── json_deserializer_error.e │ │ └── json_core_deserializer.e │ ├── interfaces │ │ ├── json_serialization_i.e │ │ └── json_serialization_context_i.e │ ├── serializer │ │ ├── json_ignore_serializer.e │ │ ├── iterable_json_serializer.e │ │ ├── json_serializer.e │ │ ├── table_iterable_json_serializer.e │ │ ├── json_core_serializer.e │ │ └── json_reflector_serializer.e │ ├── with_reference │ │ ├── json_serialization_context_with_reference.e │ │ ├── json_deserializer_context_with_reference.e │ │ ├── json_serializer_context_with_reference.e │ │ └── json_serializer_reference_collection.e │ ├── json_reflector_serialization.e │ ├── json_serialization_factory.e │ ├── support │ │ └── json_type_utilities.e │ ├── printer │ │ └── json_serialization_visitor.e │ ├── json_serialization.e │ └── json_serialization_context.e ├── converter │ ├── json_linked_list_converter.e │ ├── json_arrayed_list_converter.e │ ├── json_converter.e │ ├── support │ │ └── shared_ejson.e │ ├── json_list_converter.e │ └── json_hash_table_converter.e ├── json_gobo_extension.ecf ├── gobo_converter │ ├── shared_gobo_ejson.e │ └── converters │ │ ├── json_ds_linked_list_converter.e │ │ └── json_ds_hash_table_converter.e ├── json.ecf ├── kernel │ ├── json_null.e │ ├── json_boolean.e │ ├── json_value.e │ ├── json_array.e │ └── json_number.e └── utility │ ├── visitor │ ├── json_iterator.e │ ├── json_visitor.e │ ├── print_json_visitor.e │ └── json_pretty_string_visitor.e │ └── file │ └── json_file_reader.e ├── .gitattributes ├── package.iron ├── .travis.yml ├── History.txt ├── License.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | EIFGENs/ 3 | -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail29.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail30.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail31.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail16.json: -------------------------------------------------------------------------------- 1 | [\naked] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail33.json: -------------------------------------------------------------------------------- 1 | ["mismatch"} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail2.json: -------------------------------------------------------------------------------- 1 | ["Unclosed array" -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail24.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail4.json: -------------------------------------------------------------------------------- 1 | ["extra comma",] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail8.json: -------------------------------------------------------------------------------- 1 | ["Extra close"]] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail19.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail23.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail27.json: -------------------------------------------------------------------------------- 1 | ["line 2 | break"] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail28.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail9.json: -------------------------------------------------------------------------------- 1 | {"Extra comma": true,} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail20.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail5.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail6.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail7.json: -------------------------------------------------------------------------------- 1 | ["Comma after the close"], -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail11.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail12.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail14.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail21.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail25.json: -------------------------------------------------------------------------------- 1 | [" tab character in string "] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail15.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail17.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail22.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail3.json: -------------------------------------------------------------------------------- 1 | {unquoted_key: "keys must be quoted"} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail26.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail32.json: -------------------------------------------------------------------------------- 1 | {"Comma instead if closing brace": true, -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail13.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail18.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/pass2.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail1.json: -------------------------------------------------------------------------------- 1 | "A JSON payload should be an object or array, not a string." -------------------------------------------------------------------------------- /test/autotest/test_suite/data/fail10.json: -------------------------------------------------------------------------------- 1 | {"Extra value after close": true} "misplaced quoted value" -------------------------------------------------------------------------------- /examples/basic/basic.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | STRINGTABLE 4 | BEGIN 5 | 1 "This Program was made using EiffelStudio using Visual Studio C++" 6 | END 7 | -------------------------------------------------------------------------------- /test/autotest/test_suite/data/pass3.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /library/license.lic: -------------------------------------------------------------------------------- 1 | ${NOTE_KEYWORD} 2 | copyright: "2010-${YEAR}, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 3 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 4 | 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.e text 7 | *.ecf text 8 | *.bat text 9 | *.json text 10 | *.txt text 11 | -------------------------------------------------------------------------------- /test/autotest/test_suite/json_menu_example.txt: -------------------------------------------------------------------------------- 1 | { "menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} -------------------------------------------------------------------------------- /library/parser/json_parser_access.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Inherit to access restricted feature from {JSON_PARSER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | deferred class 7 | JSON_PARSER_ACCESS 8 | 9 | note 10 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 11 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 12 | end 13 | -------------------------------------------------------------------------------- /library/json-safe.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/autotest/test_suite/application.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "test_suite application root class" 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | APPLICATION 8 | 9 | inherit 10 | 11 | ARGUMENTS 12 | 13 | create 14 | make 15 | 16 | feature {NONE} -- Initialization 17 | 18 | make 19 | -- Run application. 20 | do 21 | --| Add your code here 22 | print ("Hello Eiffel World!%N") 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /test/autotest/test_suite/test_suite-safe.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /examples/serialization/serialization-safe.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /library/serialization/deserializer/support/linked_list_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {LINKED_LIST_JSON_DESERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | LINKED_LIST_JSON_DESERIALIZER [G -> detachable ANY] 8 | 9 | inherit 10 | LIST_JSON_DESERIALIZER [G] 11 | 12 | note 13 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 14 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 15 | end 16 | -------------------------------------------------------------------------------- /library/serialization/deserializer/support/arrayed_list_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {ARRAYED_LIST_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | ARRAYED_LIST_JSON_DESERIALIZER [G -> detachable ANY] 9 | 10 | inherit 11 | LIST_JSON_DESERIALIZER [G] 12 | 13 | note 14 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 15 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 16 | end 17 | -------------------------------------------------------------------------------- /package.iron: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | project 4 | json = "library/json.ecf" 5 | json_gobo = "library/json_gobo_extension.ecf" 6 | 7 | note 8 | title: Eiffel JSON 9 | description: "[ 10 | Eiffel JSON parser and visitors. 11 | ]" 12 | 13 | tags: json,parser,text 14 | license: MIT 15 | copyright: Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others, 16 | link[license]: "license" "https://github.com/eiffelhub/json/blob/master/License.txt" 17 | link[github]: "project" https://github.com/eiffelhub/json 18 | 19 | end 20 | -------------------------------------------------------------------------------- /examples/serialization/model/entity.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {ENTITY}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | deferred class 8 | ENTITY 9 | 10 | inherit 11 | DEBUG_OUTPUT 12 | 13 | feature -- Access 14 | 15 | name: READABLE_STRING_32 16 | deferred 17 | end 18 | 19 | feature -- Status report 20 | 21 | debug_output: READABLE_STRING_GENERAL 22 | -- String that should be displayed in debugger to represent `Current'. 23 | do 24 | Result := name 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /library/serialization/interfaces/json_serialization_i.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Common ancestor for {JSON_SERIALIZER and JSON_DESERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | deferred class 7 | JSON_SERIALIZATION_I 8 | 9 | feature -- Cleaning 10 | 11 | reset 12 | -- Clean any temporary data. 13 | --| Redefine in descendants. 14 | do 15 | end 16 | 17 | note 18 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 19 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 20 | end 21 | -------------------------------------------------------------------------------- /library/serialization/interfaces/json_serialization_context_i.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Common ancestor for {JSON_SERIALIZER_CONTEXT and JSON_DESERIALIZER_CONTEXT}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | deferred class 7 | JSON_SERIALIZATION_CONTEXT_I 8 | 9 | feature -- Cleaning 10 | 11 | reset 12 | -- Clean any temporary data. 13 | deferred 14 | end 15 | 16 | note 17 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 18 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 19 | end 20 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/model/entity.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {ENTITY}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | deferred class 8 | ENTITY 9 | 10 | inherit 11 | DEBUG_OUTPUT 12 | 13 | feature -- Access 14 | 15 | name: READABLE_STRING_32 16 | deferred 17 | end 18 | 19 | feature -- Status report 20 | 21 | debug_output: READABLE_STRING_GENERAL 22 | -- String that should be displayed in debugger to represent `Current'. 23 | do 24 | Result := name 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: eiffel 2 | before_script: 3 | - export current_dir=$PWD ; echo current_dir=$current_dir ; cd .. 4 | - export ISE_PLATFORM=linux-x86-64 5 | - curl -sSL https://www.eiffel.org/setup/install.sh | bash > eiffel.rc 6 | - source ./eiffel.rc 7 | - echo `ec -version` 8 | - cd $current_dir 9 | 10 | # safelist 11 | branches: 12 | only: 13 | - master 14 | - develop 15 | 16 | script: 17 | #compile code 18 | - compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false 19 | #testing 20 | - ec -config test/test_suite.ecf -c_compile -tests 21 | -------------------------------------------------------------------------------- /examples/serialization/custom/team_json_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON serializer and JSON deserializer implementation for APP_GROUP objects. 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | TEAM_JSON_SERIALIZATION 10 | 11 | inherit 12 | TEAM_JSON_SERIALIZER 13 | redefine 14 | reset 15 | end 16 | TEAM_JSON_DESERIALIZER 17 | redefine 18 | reset 19 | end 20 | 21 | feature -- Cleaning 22 | 23 | reset 24 | -- 25 | do 26 | Precursor {TEAM_JSON_SERIALIZER} 27 | Precursor {TEAM_JSON_DESERIALIZER} 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /library/serialization/deserializer/creation/json_deserializer_creation_callback.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_DESERIALIZER_CREATION_CALLBACK}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | deferred class 8 | JSON_DESERIALIZER_CREATION_CALLBACK 9 | 10 | feature -- Callback 11 | 12 | on_value_creation (a_value_info: JSON_DESERIALIZER_CREATION_INFORMATION) 13 | deferred 14 | end 15 | 16 | note 17 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 18 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 19 | end 20 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/model/author.e: -------------------------------------------------------------------------------- 1 | class 2 | AUTHOR 3 | 4 | create 5 | make 6 | 7 | feature {NONE} -- Initialization 8 | 9 | make (a_name: STRING_32) 10 | -- Create an author with `a_name' as `name'. 11 | do 12 | set_name (a_name) 13 | ensure 14 | name_set: name = a_name 15 | end 16 | 17 | feature -- Access 18 | 19 | name: STRING_32 20 | -- Author name 21 | 22 | feature -- Change 23 | 24 | set_name (a_name: STRING_32) 25 | -- Set `name' with `a_name'. 26 | do 27 | name := a_name 28 | ensure 29 | name_set: name = a_name 30 | end 31 | 32 | end -- class AUTHOR 33 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/team_json_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON serializer and JSON deserializer implementation for APP_GROUP objects. 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | TEAM_JSON_SERIALIZATION 10 | 11 | inherit 12 | TEAM_JSON_SERIALIZER 13 | redefine 14 | reset 15 | end 16 | TEAM_JSON_DESERIALIZER 17 | redefine 18 | reset 19 | end 20 | 21 | feature -- Cleaning 22 | 23 | reset 24 | -- 25 | do 26 | Precursor {TEAM_JSON_SERIALIZER} 27 | Precursor {TEAM_JSON_DESERIALIZER} 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /examples/serialization/custom/person_json_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON serializer and JSON deserializer implementation for APP_PERSON objects. 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | PERSON_JSON_SERIALIZATION 10 | 11 | inherit 12 | PERSON_JSON_SERIALIZER 13 | redefine 14 | reset 15 | end 16 | 17 | PERSON_JSON_DESERIALIZER 18 | redefine 19 | reset 20 | end 21 | 22 | feature -- Cleaning 23 | 24 | reset 25 | -- 26 | do 27 | Precursor {PERSON_JSON_SERIALIZER} 28 | Precursor {PERSON_JSON_DESERIALIZER} 29 | end 30 | 31 | 32 | 33 | end 34 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/person_json_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON serializer and JSON deserializer implementation for APP_PERSON objects. 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | PERSON_JSON_SERIALIZATION 10 | 11 | inherit 12 | PERSON_JSON_SERIALIZER 13 | redefine 14 | reset 15 | end 16 | 17 | PERSON_JSON_DESERIALIZER 18 | redefine 19 | reset 20 | end 21 | 22 | feature -- Cleaning 23 | 24 | reset 25 | -- 26 | do 27 | Precursor {PERSON_JSON_SERIALIZER} 28 | Precursor {PERSON_JSON_DESERIALIZER} 29 | end 30 | 31 | 32 | 33 | end 34 | -------------------------------------------------------------------------------- /examples/serialization/model/team.e: -------------------------------------------------------------------------------- 1 | class 2 | TEAM 3 | 4 | inherit 5 | ENTITY 6 | 7 | create 8 | make 9 | 10 | feature {NONE} -- Initialization 11 | 12 | make (a_name: READABLE_STRING_GENERAL) 13 | do 14 | create name.make_from_string_general (a_name) 15 | create {ARRAYED_LIST [PERSON]} persons.make (0) 16 | end 17 | 18 | feature -- Access 19 | 20 | name: IMMUTABLE_STRING_32 21 | 22 | persons: LIST [PERSON] 23 | 24 | owner: detachable PERSON 25 | 26 | feature -- Element change 27 | 28 | set_owner (p: detachable PERSON) 29 | do 30 | owner := p 31 | end 32 | 33 | put (a_person: PERSON) 34 | do 35 | persons.extend (a_person) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /library/serialization/serializer/json_ignore_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Serializer to ignore a specific type of object. 4 | 5 | Register it using the {TYPE_NAME} you want to ignore. 6 | ]" 7 | date: "$Date$" 8 | revision: "$Revision$" 9 | 10 | class 11 | JSON_IGNORE_SERIALIZER [G] 12 | 13 | inherit 14 | JSON_SERIALIZER 15 | 16 | feature -- Conversion 17 | 18 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 19 | do 20 | create {JSON_NULL} Result 21 | end 22 | 23 | note 24 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 25 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 26 | end 27 | -------------------------------------------------------------------------------- /examples/serialization/serialization.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/basic/basic.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/run_autotest.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set TMP_EC_SCRIPT_FILENAME=%~dp0.tmp_ec_scripting 4 | 5 | cd %~dp0autotest\test_suite 6 | set TMP_EC_CMD=ec -config test_suite-safe.ecf -target test_suite -batch 7 | 8 | echo # Fresh Compilation 9 | %TMP_EC_CMD% -batch -clean -freeze -c_compile -project_path . > %~dp0autotest.compile.log 2>&1 10 | 11 | rem Build scripting for freeze + testing 12 | rem ------------------------------------ 13 | rem Testing 14 | echo T > %TMP_EC_SCRIPT_FILENAME% 15 | rem Execute 16 | echo e >> %TMP_EC_SCRIPT_FILENAME% 17 | rem Quit 18 | echo Q >> %TMP_EC_SCRIPT_FILENAME% 19 | 20 | echo # Execute test_suite 21 | type %TMP_EC_SCRIPT_FILENAME% | %TMP_EC_CMD% -loop 1> :NULL 2> %~dp0autotest.testing.log 22 | type %~dp0autotest.testing.log 23 | 24 | cd %~dp0 25 | 26 | del %TMP_EC_SCRIPT_FILENAME% 27 | endlocal 28 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | History file for EJSON 2 | ====================== 3 | 4 | team: "" 5 | date: "2011-07-06" 6 | revision: "0.3.0" 7 | 8 | WARNING: THIS FILE IS NOT UP TO DATE 9 | 10 | 11 | +++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++ 12 | 13 | *Updated skip_white_spaces, now check %U and %T codes 14 | 15 | *Undo changes to is_a_valid_number, because it's doesn't follow the 16 | JSON spec. Tests : fail13.json, fail29.json and fail30.json are valid 17 | with this implementation, so we go back to the previous 18 | implementation. 19 | 20 | *Added autotest test suite 21 | 22 | *Added getest based test program 23 | 24 | *Updated Eiffel configuration file, updated to the new clusters 25 | 26 | *Added converters and factory classes 27 | 28 | *Added new top level directories; library, test, build and example 29 | -------------------------------------------------------------------------------- /library/converter/json_linked_list_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for LINKED_LIST [ANY]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | class 9 | JSON_LINKED_LIST_CONVERTER 10 | 11 | obsolete 12 | "This JSON converter design has issues [Sept/2014]." 13 | 14 | inherit 15 | 16 | JSON_LIST_CONVERTER 17 | redefine 18 | object 19 | end 20 | 21 | create 22 | make 23 | 24 | feature -- Access 25 | 26 | object: LINKED_LIST [detachable ANY] 27 | 28 | feature {NONE} -- Factory 29 | 30 | new_object (nb: INTEGER): like object 31 | do 32 | create Result.make 33 | end 34 | 35 | note 36 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 37 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 38 | end -- class JSON_LINKED_LIST_CONVERTER 39 | -------------------------------------------------------------------------------- /library/converter/json_arrayed_list_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for ARRAYED_LIST [ANY]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | class 9 | JSON_ARRAYED_LIST_CONVERTER 10 | 11 | obsolete 12 | "This JSON converter design has issues [Sept/2014]." 13 | 14 | inherit 15 | 16 | JSON_LIST_CONVERTER 17 | redefine 18 | object 19 | end 20 | 21 | create 22 | make 23 | 24 | feature -- Access 25 | 26 | object: ARRAYED_LIST [detachable ANY] 27 | 28 | feature {NONE} -- Factory 29 | 30 | new_object (nb: INTEGER): like object 31 | do 32 | create Result.make (nb) 33 | end 34 | 35 | note 36 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 37 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 38 | end -- class JSON_ARRAYED_LIST_CONVERTER 39 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/model/person_details.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_DETAILS}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_DETAILS 9 | 10 | feature -- Access 11 | 12 | city_name: detachable IMMUTABLE_STRING_32 13 | 14 | zip: INTEGER 15 | 16 | country: detachable IMMUTABLE_STRING_32 17 | 18 | feature -- Element change 19 | 20 | set_zip (a_zip: INTEGER) 21 | do 22 | zip := a_zip 23 | end 24 | 25 | set_country (s: detachable READABLE_STRING_GENERAL) 26 | do 27 | if s = Void then 28 | country := Void 29 | else 30 | create country.make_from_string_general (s) 31 | end 32 | end 33 | 34 | set_city_name (s: detachable READABLE_STRING_GENERAL) 35 | do 36 | if s = Void then 37 | city_name := Void 38 | else 39 | create city_name.make_from_string_general (s) 40 | end 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /library/serialization/deserializer/creation/json_deserializer_creation_agent_callback.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_DESERIALIZER_CREATION_AGENT_CALLBACK}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_DESERIALIZER_CREATION_AGENT_CALLBACK 9 | 10 | inherit 11 | JSON_DESERIALIZER_CREATION_CALLBACK 12 | 13 | create 14 | make 15 | 16 | feature -- Initialization 17 | 18 | make (agt: like action) 19 | do 20 | action := agt 21 | end 22 | 23 | feature -- Access 24 | 25 | action: PROCEDURE [TUPLE [JSON_DESERIALIZER_CREATION_INFORMATION]] 26 | 27 | feature -- Callback 28 | 29 | on_value_creation (a_value_info: JSON_DESERIALIZER_CREATION_INFORMATION) 30 | do 31 | action.call (a_value_info) 32 | end 33 | 34 | note 35 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 36 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 37 | end 38 | -------------------------------------------------------------------------------- /library/serialization/with_reference/json_serialization_context_with_reference.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON Serialization context for JSON serializer and JSON deserializer. 4 | 5 | By default, it is using the reflection mechanism. 6 | But this should be applied only on recursively "expanded" object (i.e without any cycle). 7 | ]" 8 | date: "$Date$" 9 | revision: "$Revision$" 10 | 11 | class 12 | JSON_SERIALIZATION_CONTEXT_WITH_REFERENCE 13 | 14 | inherit 15 | JSON_SERIALIZATION_CONTEXT 16 | redefine 17 | serializer_context, 18 | deserializer_context 19 | end 20 | 21 | create 22 | default_create 23 | 24 | feature -- Access 25 | 26 | serializer_context: JSON_SERIALIZER_CONTEXT_WITH_REFERENCE 27 | 28 | deserializer_context: JSON_DESERIALIZER_CONTEXT_WITH_REFERENCE 29 | 30 | invariant 31 | 32 | note 33 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 34 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 35 | end 36 | -------------------------------------------------------------------------------- /library/serialization/json_reflector_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON serialization and deserialization based on reflexion mechanism. 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | JSON_REFLECTOR_SERIALIZATION 10 | 11 | inherit 12 | JSON_REFLECTOR_SERIALIZER 13 | redefine 14 | default_create, 15 | reset 16 | end 17 | 18 | JSON_REFLECTOR_DESERIALIZER 19 | redefine 20 | default_create, 21 | reset 22 | end 23 | 24 | create 25 | default_create 26 | 27 | feature {NONE} -- Initialization 28 | 29 | default_create 30 | do 31 | Precursor {JSON_REFLECTOR_SERIALIZER} 32 | Precursor {JSON_REFLECTOR_DESERIALIZER} 33 | end 34 | 35 | feature -- Cleaning 36 | 37 | reset 38 | do 39 | Precursor {JSON_REFLECTOR_SERIALIZER} 40 | Precursor {JSON_REFLECTOR_DESERIALIZER} 41 | end 42 | 43 | note 44 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 45 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 46 | end 47 | -------------------------------------------------------------------------------- /library/json_gobo_extension.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | /\.git$ 7 | /\.svn$ 8 | /EIFGENs$ 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /library/converter/json_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | deferred class 9 | JSON_CONVERTER 10 | 11 | obsolete 12 | "This JSON converter design has issues [Sept/2014]." 13 | 14 | inherit 15 | 16 | SHARED_EJSON 17 | 18 | feature -- Access 19 | 20 | object: ANY 21 | -- Eiffel object 22 | deferred 23 | end 24 | 25 | feature -- Conversion 26 | 27 | from_json (j: attached like to_json): detachable like object 28 | -- Convert from JSON value. 29 | -- Returns Void if unable to convert 30 | deferred 31 | end 32 | 33 | to_json (o: like object): detachable JSON_VALUE 34 | -- Convert to JSON value 35 | deferred 36 | end 37 | 38 | invariant 39 | has_eiffel_object: object /= Void -- An empty object must be created at creation time! 40 | 41 | note 42 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 43 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 44 | end 45 | -------------------------------------------------------------------------------- /library/gobo_converter/shared_gobo_ejson.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Shared factory class for creating JSON objects. Maps JSON 4 | objects to Gobo DS_HASH_TABLEs and JSON arrays to Gobo 5 | DS_LINKED_LISTs. Use non-conforming inheritance from this 6 | class to ensure that your classes share the same 7 | JSON_FACTORY instance. 8 | ]" 9 | author: "Paul Cohen" 10 | date: "$Date$" 11 | revision: "$Revision$" 12 | file: "$HeadURL$" 13 | 14 | class SHARED_GOBO_EJSON 15 | 16 | feature 17 | 18 | json: EJSON 19 | -- A shared EJSON instance with default converters for 20 | -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE] 21 | local 22 | jllc: JSON_DS_LINKED_LIST_CONVERTER 23 | jhtc: JSON_DS_HASH_TABLE_CONVERTER 24 | once 25 | create Result 26 | create jllc.make 27 | Result.add_converter (jllc) 28 | create jhtc.make 29 | Result.add_converter (jhtc) 30 | end 31 | 32 | end -- class SHARED_GOBO_EJSON 33 | -------------------------------------------------------------------------------- /examples/serialization/custom/person_details_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_DETAILS_JSON_SERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_DETAILS_JSON_SERIALIZER 9 | 10 | inherit 11 | JSON_SERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 16 | local 17 | j_object: JSON_OBJECT 18 | do 19 | if attached {PERSON_DETAILS} obj as details then 20 | create j_object.make_with_capacity (3) 21 | 22 | ctx.on_object_serialization_start (details) 23 | -- "city_name" 24 | if attached details.city_name as l_city_name then 25 | j_object.put_string (l_city_name, "city_name") 26 | end 27 | -- "zip" 28 | j_object.put_integer (details.zip, "zip") 29 | 30 | -- "country" 31 | if attached details.country as l_country then 32 | j_object.put_string (l_country, "country") 33 | end 34 | Result := j_object 35 | ctx.on_object_serialization_end (j_object, details) 36 | else 37 | create {JSON_NULL} Result 38 | end 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/model/person.e: -------------------------------------------------------------------------------- 1 | class 2 | PERSON 3 | 4 | inherit 5 | ENTITY 6 | 7 | create 8 | make 9 | 10 | feature {NONE} -- Initialization 11 | 12 | make (a_first_name, a_last_name: READABLE_STRING_GENERAL) 13 | do 14 | create first_name.make_from_string_general (a_first_name) 15 | create last_name.make_from_string_general (a_last_name) 16 | create {ARRAYED_LIST [ENTITY]} co_workers.make (0) 17 | end 18 | 19 | feature -- Access 20 | 21 | first_name: IMMUTABLE_STRING_32 22 | 23 | last_name: IMMUTABLE_STRING_32 24 | 25 | details: detachable PERSON_DETAILS 26 | 27 | co_workers: LIST [ENTITY] 28 | 29 | feature -- Element change 30 | 31 | set_details (d: like details) 32 | do 33 | details := d 34 | end 35 | 36 | add_co_worker (e: ENTITY) 37 | do 38 | co_workers.force (e) 39 | end 40 | 41 | feature -- Status report 42 | 43 | name: STRING_32 44 | -- String that should be displayed in debugger to represent `Current'. 45 | do 46 | create Result.make_from_string (first_name) 47 | Result.append_character (' ') 48 | Result.append (last_name) 49 | end 50 | 51 | invariant 52 | 53 | end 54 | -------------------------------------------------------------------------------- /examples/performance/basic.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/serialization/model/person_details.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_DETAILS}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_DETAILS 9 | 10 | create 11 | make 12 | 13 | feature {NONE} -- Initialization 14 | 15 | make (a_zip: INTEGER; a_city, a_country: READABLE_STRING_GENERAL) 16 | do 17 | zip := a_zip 18 | set_city_name (a_city) 19 | set_country (a_country) 20 | end 21 | 22 | feature -- Access 23 | 24 | city_name: detachable IMMUTABLE_STRING_32 25 | 26 | zip: INTEGER 27 | 28 | country: detachable IMMUTABLE_STRING_32 29 | 30 | feature -- Element change 31 | 32 | set_zip (a_zip: INTEGER) 33 | do 34 | zip := a_zip 35 | end 36 | 37 | set_country (s: detachable READABLE_STRING_GENERAL) 38 | do 39 | if s = Void then 40 | country := Void 41 | else 42 | create country.make_from_string_general (s) 43 | end 44 | end 45 | 46 | set_city_name (s: detachable READABLE_STRING_GENERAL) 47 | do 48 | if s = Void then 49 | city_name := Void 50 | else 51 | create city_name.make_from_string_general (s) 52 | end 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/json_author_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for AUTHOR" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_AUTHOR_CONVERTER 9 | 10 | inherit 11 | 12 | JSON_CONVERTER 13 | 14 | create 15 | make 16 | 17 | feature {NONE} -- Initialization 18 | 19 | make 20 | local 21 | ucs: STRING_32 22 | do 23 | create ucs.make_from_string ("") 24 | create object.make (ucs) 25 | end 26 | 27 | feature -- Access 28 | 29 | object: AUTHOR 30 | 31 | feature -- Conversion 32 | 33 | from_json (j: like to_json): detachable like object 34 | do 35 | if attached {STRING_32} json.object (j.item (name_key), Void) as l_name then 36 | create Result.make (l_name) 37 | end 38 | end 39 | 40 | to_json (o: like object): JSON_OBJECT 41 | do 42 | create Result.make 43 | Result.put (json.value (o.name), name_key) 44 | end 45 | 46 | feature {NONE} -- Implementation 47 | 48 | name_key: JSON_STRING 49 | -- Author's name label. 50 | once 51 | create Result.make_from_string ("name") 52 | end 53 | 54 | end -- class JSON_AUTHOR_CONVERTER 55 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/person_details_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_DETAILS_JSON_SERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_DETAILS_JSON_SERIALIZER 9 | 10 | inherit 11 | JSON_SERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 16 | local 17 | j_object: JSON_OBJECT 18 | do 19 | if attached {PERSON_DETAILS} obj as details then 20 | create j_object.make_with_capacity (3) 21 | 22 | ctx.on_object_serialization_start (details) 23 | -- "city_name" 24 | if attached details.city_name as l_city_name then 25 | j_object.put_string (l_city_name, "city_name") 26 | end 27 | -- "zip" 28 | j_object.put_integer (details.zip, "zip") 29 | 30 | -- "country" 31 | if attached details.country as l_country then 32 | j_object.put_string (l_country, "country") 33 | end 34 | Result := j_object 35 | ctx.on_object_serialization_end (j_object, details) 36 | else 37 | create {JSON_NULL} Result 38 | end 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others, 2 | https://github.com/eiffelhub/json . 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /library/serialization/deserializer/json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON deserializer." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | deferred class 7 | JSON_DESERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZATION_I 11 | 12 | feature -- Conversion 13 | 14 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable ANY 15 | -- Eiffel value deserialized from `a_json' value, in the eventual context `ctx'. 16 | deferred 17 | end 18 | 19 | from_json_string (a_json_string: READABLE_STRING_8; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable ANY 20 | -- Eiffel value deserialized from `a_json' content string, in the eventual context `ctx'. 21 | local 22 | p: JSON_PARSER 23 | do 24 | create p.make_with_string (a_json_string) 25 | p.parse_content 26 | if 27 | p.is_parsed and then p.is_valid 28 | then 29 | Result := from_json (p.parsed_json_value, ctx, a_type) 30 | end 31 | end 32 | 33 | note 34 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 35 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 36 | end 37 | -------------------------------------------------------------------------------- /examples/serialization/model/person.e: -------------------------------------------------------------------------------- 1 | class 2 | PERSON 3 | 4 | inherit 5 | ENTITY 6 | 7 | create 8 | make 9 | 10 | feature {NONE} -- Initialization 11 | 12 | make (a_first_name, a_last_name: READABLE_STRING_GENERAL) 13 | do 14 | create first_name.make_from_string_general (a_first_name) 15 | create last_name.make_from_string_general (a_last_name) 16 | end 17 | 18 | feature -- Access 19 | 20 | first_name: IMMUTABLE_STRING_32 21 | 22 | last_name: IMMUTABLE_STRING_32 23 | 24 | details: detachable PERSON_DETAILS 25 | 26 | co_workers: detachable LIST [ENTITY] 27 | 28 | feature -- Element change 29 | 30 | set_details (d: like details) 31 | do 32 | details := d 33 | end 34 | 35 | add_co_worker (e: ENTITY) 36 | local 37 | lst: like co_workers 38 | do 39 | lst := co_workers 40 | if lst = Void then 41 | create {ARRAYED_LIST [ENTITY]} lst.make (0) 42 | co_workers := lst 43 | end 44 | lst.force (e) 45 | end 46 | 47 | feature -- Status report 48 | 49 | name: STRING_32 50 | -- String that should be displayed in debugger to represent `Current'. 51 | do 52 | create Result.make_from_string (first_name) 53 | Result.append_character (' ') 54 | Result.append (last_name) 55 | end 56 | 57 | invariant 58 | 59 | end 60 | -------------------------------------------------------------------------------- /library/json.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | JSON parser 4 | 5 | 6 | 7 | /.svn$ 8 | /CVS$ 9 | /EIFGENs$ 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/model/book.e: -------------------------------------------------------------------------------- 1 | class 2 | BOOK 3 | 4 | create 5 | make 6 | 7 | feature {NONE} -- Initialization 8 | 9 | make (a_title: STRING_32; a_author: AUTHOR; a_isbn: STRING_32) 10 | -- Create a book with `a_title' as `title', 11 | -- `a_author' as `author', and `a_isbn' as `isbn'. 12 | do 13 | set_title (a_title) 14 | set_author (a_author) 15 | set_isbn (a_isbn) 16 | ensure 17 | title_set: title = a_title 18 | author_set: author = a_author 19 | isbn_set: isbn = a_isbn 20 | end 21 | 22 | feature -- Access 23 | 24 | title: STRING_32 25 | -- Main title. 26 | 27 | isbn: STRING_32 28 | -- ISBN. 29 | 30 | author: AUTHOR 31 | -- Author. 32 | 33 | feature -- Change 34 | 35 | set_title (a_title: STRING_32) 36 | -- Set `title' with `a_title'. 37 | do 38 | title := a_title 39 | ensure 40 | title_set: title = a_title 41 | end 42 | 43 | set_author (a_author: AUTHOR) 44 | -- Set `author' with `a_author'. 45 | do 46 | author := a_author 47 | ensure 48 | author_set: author = a_author 49 | end 50 | 51 | set_isbn (a_isbn: STRING_32) 52 | -- Set `isbn' with `a_isbn'. 53 | do 54 | isbn := a_isbn 55 | ensure 56 | isbn_set: isbn = a_isbn 57 | end 58 | 59 | end -- class BOOK 60 | -------------------------------------------------------------------------------- /examples/serialization/custom/team_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEAM_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | TEAM_JSON_DESERIALIZER 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable TEAM 16 | do 17 | if attached {JSON_OBJECT} a_json as j_team then 18 | if 19 | attached {JSON_STRING} j_team.item ("name") as j_name 20 | then 21 | create Result.make (j_name.unescaped_string_32) 22 | if attached {JSON_OBJECT} j_team.item ("owner") as j_owner then 23 | if attached {PERSON} ctx.value_from_json (a_json, {PERSON}) as p then 24 | Result.set_owner (p) 25 | end 26 | end 27 | if attached {JSON_ARRAY} j_team.item ("persons") as j_persons then 28 | if attached ctx.deserializer ({PERSON}) as conv then 29 | across 30 | j_persons as ic 31 | loop 32 | if attached {PERSON} ctx.value_from_json (ic.item, {PERSON}) as l_person then 33 | Result.put (l_person) 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/model/team.e: -------------------------------------------------------------------------------- 1 | class 2 | TEAM 3 | 4 | inherit 5 | ENTITY 6 | 7 | create 8 | make 9 | 10 | feature {NONE} -- Initialization 11 | 12 | make (a_name: READABLE_STRING_GENERAL) 13 | do 14 | create name.make_from_string_general (a_name) 15 | create {ARRAYED_LIST [PERSON]} persons.make (0) 16 | create vectors.make_empty (3) 17 | add_vector ("abc") 18 | add_vector ("def") 19 | add_vector ("ghi") 20 | 21 | create dico.make (3) 22 | dico.force ("value1", "key1") 23 | dico.force ("value2", "key2") 24 | dico.force ("value3", "key3") 25 | end 26 | 27 | feature -- Access 28 | 29 | name: IMMUTABLE_STRING_32 30 | 31 | persons: LIST [PERSON] 32 | 33 | owner: detachable PERSON 34 | 35 | vectors: SPECIAL [STRING] 36 | 37 | dico: STRING_TABLE [READABLE_STRING_32] 38 | 39 | feature -- Element change 40 | 41 | set_owner (p: detachable PERSON) 42 | do 43 | owner := p 44 | end 45 | 46 | put (a_person: PERSON) 47 | do 48 | persons.extend (a_person) 49 | end 50 | 51 | add_vector (s: STRING) 52 | local 53 | n: INTEGER 54 | do 55 | n := vectors.count 56 | if n >= vectors.capacity then 57 | vectors := vectors.resized_area (n + 1) 58 | end 59 | vectors.extend (s) 60 | end 61 | 62 | invariant 63 | 64 | end 65 | -------------------------------------------------------------------------------- /library/converter/support/shared_ejson.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Shared factory class for creating JSON objects. Maps JSON 4 | objects to ELKS HASH_TABLEs and JSON arrays to ELKS 5 | LINKED_LISTs. Use non-conforming inheritance from this 6 | class to ensure that your classes share the same 7 | JSON_FACTORY instance. 8 | ]" 9 | author: "Paul Cohen" 10 | date: "$Date$" 11 | revision: "$Revision$" 12 | file: "$HeadURL$" 13 | 14 | class 15 | SHARED_EJSON 16 | 17 | obsolete 18 | "This JSON converter design has issues [2014-10-01]." 19 | 20 | feature -- Access 21 | 22 | json: EJSON 23 | -- A shared EJSON instance with default converters for 24 | --LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE] 25 | obsolete 26 | "Use JSON_SERIALIZATION as replacement [2017-11-15]." 27 | local 28 | jalc: JSON_ARRAYED_LIST_CONVERTER 29 | jllc: JSON_LINKED_LIST_CONVERTER 30 | jhtc: JSON_HASH_TABLE_CONVERTER 31 | once 32 | create Result 33 | create jalc.make 34 | Result.add_converter (jalc) 35 | create jllc.make 36 | Result.add_converter (jllc) 37 | create jhtc.make 38 | Result.add_converter (jhtc) 39 | end 40 | 41 | note 42 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 43 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 44 | 45 | end -- class SHARED_EJSON 46 | -------------------------------------------------------------------------------- /library/kernel/json_null.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Null Values" 3 | author: "Javier Velilla" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_NULL 9 | 10 | inherit 11 | JSON_VALUE 12 | redefine 13 | is_null 14 | end 15 | 16 | feature -- Status report 17 | 18 | is_null: BOOLEAN = True 19 | -- 20 | 21 | feature -- Access 22 | 23 | hash_code: INTEGER 24 | -- Hash code value 25 | do 26 | Result := null_value.hash_code 27 | end 28 | 29 | feature -- Conversion 30 | 31 | representation: STRING 32 | do 33 | Result := "null" 34 | ensure then 35 | instance_free: class 36 | end 37 | 38 | feature -- Visitor pattern 39 | 40 | accept (a_visitor: JSON_VISITOR) 41 | -- Accept `a_visitor'. 42 | -- (Call `visit_element_a' procedure on `a_visitor'.) 43 | do 44 | a_visitor.visit_json_null (Current) 45 | end 46 | 47 | feature -- Status report 48 | 49 | debug_output: STRING 50 | -- String that should be displayed in debugger to represent `Current'. 51 | do 52 | Result := null_value 53 | end 54 | 55 | feature {NONE} -- Implementation 56 | 57 | null_value: STRING = "null" 58 | 59 | note 60 | copyright: "2010-2019, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 61 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 62 | end 63 | -------------------------------------------------------------------------------- /library/serialization/deserializer/basic/json_basic_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON deserializer based on reflection mechanism." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_BASIC_DESERIALIZER [G -> detachable ANY] 8 | 9 | inherit 10 | JSON_CORE_DESERIALIZER 11 | redefine 12 | from_json, 13 | reset 14 | end 15 | 16 | JSON_TYPE_UTILITIES 17 | 18 | feature -- Conversion 19 | 20 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable ANY 21 | local 22 | obj_conv: TABLE_JSON_DESERIALIZER [G] 23 | arr_conv: ARRAYED_LIST_JSON_DESERIALIZER [G] 24 | do 25 | if attached {JSON_OBJECT} a_json as j_object then 26 | create obj_conv 27 | Result := obj_conv.from_json (a_json, ctx, Void) 28 | elseif attached {JSON_ARRAY} a_json as j_array then 29 | create arr_conv 30 | Result := arr_conv.from_json (a_json, ctx, Void) 31 | else 32 | Result := Precursor (a_json, ctx, a_type) 33 | end 34 | if ctx.has_error then 35 | Result := Void 36 | end 37 | end 38 | 39 | feature -- Cleaning 40 | 41 | reset 42 | -- 43 | do 44 | end 45 | 46 | note 47 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 48 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 49 | end 50 | -------------------------------------------------------------------------------- /test/autotest/test_suite/test_suite.ecf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | /EIFGENs$ 7 | /\.git$ 8 | /\.svn$ 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | /obsolete$ 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /library/utility/visitor/json_iterator.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Iterator" 3 | pattern: "Iterator visitor" 4 | author: "Jocelyn Fiat" 5 | license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" 6 | date: "$Date$" 7 | revision: "$Revision$" 8 | 9 | deferred class 10 | JSON_ITERATOR 11 | 12 | inherit 13 | 14 | JSON_VISITOR 15 | 16 | feature -- Visitor Pattern 17 | 18 | visit_json_array (a_json_array: JSON_ARRAY) 19 | -- Visit `a_json_array'. 20 | do 21 | across 22 | a_json_array as c 23 | loop 24 | c.item.accept (Current) 25 | end 26 | end 27 | 28 | visit_json_boolean (a_json_boolean: JSON_BOOLEAN) 29 | -- Visit `a_json_boolean'. 30 | do 31 | end 32 | 33 | visit_json_null (a_json_null: JSON_NULL) 34 | -- Visit `a_json_null'. 35 | do 36 | end 37 | 38 | visit_json_number (a_json_number: JSON_NUMBER) 39 | -- Visit `a_json_number'. 40 | do 41 | end 42 | 43 | visit_json_object (a_json_object: JSON_OBJECT) 44 | -- Visit `a_json_object'. 45 | do 46 | across 47 | a_json_object as c 48 | loop 49 | c.item.accept (Current) 50 | end 51 | end 52 | 53 | visit_json_string (a_json_string: JSON_STRING) 54 | -- Visit `a_json_string'. 55 | do 56 | end 57 | 58 | note 59 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 60 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 61 | end 62 | -------------------------------------------------------------------------------- /examples/serialization/output_utilities.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {OUTPUT_UTILITIES}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | OUTPUT_UTILITIES 8 | 9 | feature -- Output 10 | 11 | output_object (obj: detachable ANY; a_offset: STRING) 12 | local 13 | l_offset: STRING 14 | do 15 | -- Warning: it should use the localication printer due to potential unicode value... 16 | if obj = Void then 17 | print ("Void") 18 | print ("%N") 19 | elseif attached {READABLE_STRING_GENERAL} obj as str then 20 | print ("%"") 21 | print (str) 22 | print ("%"%N") 23 | elseif attached {TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]} obj as tb then 24 | print (tb.generator + " {%N") 25 | l_offset := a_offset + " " 26 | across 27 | tb as ic 28 | loop 29 | print (l_offset) 30 | print (ic.key) 31 | print (" => ") 32 | output_object (ic.item, l_offset + " ") 33 | end 34 | print (a_offset) 35 | print ("}%N") 36 | elseif attached {ITERABLE [detachable ANY]} obj as lst then 37 | print (lst.generator + " [%N") 38 | l_offset := a_offset + " " 39 | across 40 | lst as ic 41 | loop 42 | print (l_offset) 43 | output_object (ic.item, l_offset + " ") 44 | end 45 | print (a_offset) 46 | print ("]%N") 47 | else 48 | print (obj) 49 | print ("%N") 50 | end 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /library/serialization/deserializer/creation/json_deserializer_creation_information.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_DESERIALIZER_CREATION_INFORMATION}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_DESERIALIZER_CREATION_INFORMATION 9 | 10 | create 11 | make 12 | 13 | feature {NONE} -- Initialization 14 | 15 | make (a_static_type: detachable TYPE [detachable ANY]; a_json: detachable JSON_VALUE) 16 | do 17 | static_type := a_static_type 18 | json_value := a_json 19 | end 20 | 21 | feature -- Access 22 | 23 | static_type: detachable TYPE [detachable ANY] 24 | 25 | json_value: detachable JSON_VALUE assign set_json_value 26 | 27 | parent_object: detachable ANY 28 | 29 | feature_name: detachable READABLE_STRING_GENERAL 30 | 31 | feature -- Response 32 | 33 | object: detachable ANY 34 | -- Provide expected object. 35 | 36 | feature -- Element change 37 | 38 | set_json_value (a_value: like json_value) 39 | do 40 | json_value := a_value 41 | end 42 | 43 | set_parent_object (o: detachable ANY) 44 | do 45 | parent_object := o 46 | end 47 | 48 | set_feature_name (fn: detachable READABLE_STRING_GENERAL) 49 | do 50 | feature_name := fn 51 | end 52 | 53 | set_object (obj: like object) 54 | do 55 | object := obj 56 | end 57 | 58 | 59 | ;note 60 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 61 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 62 | end 63 | -------------------------------------------------------------------------------- /library/serialization/serializer/iterable_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {ITERABLE_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | ITERABLE_JSON_SERIALIZER [G -> detachable ANY] 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | -- JSON value representing the JSON serialization of Eiffel value `obj', in the eventual context `ctx'. 16 | local 17 | i: INTEGER 18 | j_array: JSON_ARRAY 19 | do 20 | if attached {ITERABLE [G]} obj as arr then 21 | -- Is this a good idea? 22 | -- what about object exporting an ITERABLE interface, but containing other attributes 23 | -- unrelated to that iterable nature! 24 | create j_array.make_empty 25 | i := 0 26 | across 27 | arr as ic 28 | loop 29 | i := i + 1 30 | ctx.on_field_start (i.out) 31 | if 32 | attached ic.item as l_item and then 33 | attached ctx.to_json (l_item, Current) as j_value 34 | then 35 | j_array.extend (j_value) 36 | else 37 | j_array.extend (create {JSON_NULL}) 38 | end 39 | ctx.on_field_end (i.out) 40 | end 41 | Result := j_array 42 | else 43 | create {JSON_NULL} Result 44 | end 45 | end 46 | 47 | note 48 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 49 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 50 | end 51 | -------------------------------------------------------------------------------- /library/serialization/deserializer/json_deserializer_error.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_DESERIALIZER_ERROR}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_DESERIALIZER_ERROR 9 | 10 | inherit 11 | ANY 12 | redefine 13 | default_create 14 | end 15 | 16 | create 17 | make, 18 | default_create 19 | 20 | convert 21 | make ({READABLE_STRING_GENERAL, READABLE_STRING_8, READABLE_STRING_32, STRING_8, STRING_32}) 22 | 23 | feature {NONE} -- Initialization 24 | 25 | default_create 26 | do 27 | make ("Deserialization error!") 28 | end 29 | 30 | make (a_message: READABLE_STRING_GENERAL) 31 | do 32 | create message.make_from_string_general (a_message) 33 | end 34 | 35 | feature -- Access 36 | 37 | message: IMMUTABLE_STRING_32 38 | 39 | previous: detachable JSON_DESERIALIZER_ERROR 40 | 41 | feature -- Conversion 42 | 43 | all_messages_as_string: STRING_32 44 | do 45 | create Result.make_empty 46 | append_all_messages_to (Result) 47 | end 48 | 49 | append_all_messages_to (s: STRING_32) 50 | do 51 | s.append (message) 52 | if attached previous as prev then 53 | prev.append_all_messages_to (s) 54 | end 55 | end 56 | 57 | feature -- Element change 58 | 59 | set_previous (e: like previous) 60 | do 61 | previous := e 62 | end 63 | 64 | ;note 65 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 66 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 67 | end 68 | -------------------------------------------------------------------------------- /library/utility/file/json_file_reader.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Objects that ..." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_FILE_READER 9 | 10 | feature -- Access 11 | 12 | read_json_from (a_path: READABLE_STRING_GENERAL): detachable STRING 13 | local 14 | l_file: PLAIN_TEXT_FILE 15 | l_last_string: detachable STRING 16 | l_file_count: INTEGER 17 | l_fetch_done: BOOLEAN 18 | do 19 | create l_file.make_with_name (a_path) 20 | -- We perform several checks until we make a real attempt to open the file. 21 | if not l_file.exists then 22 | print ("error: '" + a_path.out + "' does not exist%N") -- FIXME: unicode may be truncated 23 | else 24 | if not l_file.is_readable then 25 | print ("error: '" + a_path.out + "' is not readable.%N") -- FIXME: unicode may be truncated 26 | else 27 | l_file_count := l_file.count 28 | l_file.open_read 29 | from 30 | create Result.make (l_file_count) 31 | until 32 | l_fetch_done 33 | loop 34 | l_file.read_stream (1_024) 35 | l_last_string := l_file.last_string 36 | l_fetch_done := l_file.exhausted or l_file.end_of_file or l_last_string.count < 1_024 37 | if not l_last_string.is_empty then 38 | Result.append (l_last_string) 39 | end 40 | end 41 | l_file.close 42 | end 43 | end 44 | end 45 | 46 | note 47 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 48 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 49 | end 50 | -------------------------------------------------------------------------------- /library/serialization/json_serialization_factory.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_SERIALIZATION_FACTORY}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | expanded class 8 | JSON_SERIALIZATION_FACTORY 9 | 10 | feature -- Factory 11 | 12 | serialization: JSON_SERIALIZATION 13 | -- Simple empty serialization. 14 | -- It requires either custom (de)serializers or reflector based solution. 15 | do 16 | create Result 17 | end 18 | 19 | reflector_serialization: JSON_SERIALIZATION 20 | do 21 | Result := serialization 22 | Result.register_default (create {JSON_REFLECTOR_SERIALIZATION}) 23 | end 24 | 25 | smart_serialization: JSON_SERIALIZATION 26 | -- Serialization based on reflector, but with specific handling of ITERABLE, LIST and TABLE objects. 27 | do 28 | Result := reflector_serialization 29 | 30 | -- Serializers 31 | Result.register (create {TABLE_ITERABLE_JSON_SERIALIZER [detachable ANY, READABLE_STRING_GENERAL]}, {TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]}) 32 | Result.register (create {ITERABLE_JSON_SERIALIZER [detachable ANY]}, {ITERABLE [detachable ANY]}) 33 | -- Deserializers 34 | Result.register (create {TABLE_JSON_DESERIALIZER [detachable ANY]}, {TABLE [detachable ANY, READABLE_STRING_GENERAL]}) 35 | Result.register (create {LIST_JSON_DESERIALIZER [detachable ANY]}, {LIST [detachable ANY]}) 36 | end 37 | 38 | note 39 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 40 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 41 | end 42 | -------------------------------------------------------------------------------- /library/utility/visitor/json_visitor.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Visitor" 3 | pattern: "Visitor" 4 | author: "Javier Velilla" 5 | license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" 6 | date: "$Date$" 7 | revision: "$Revision$" 8 | 9 | deferred class 10 | JSON_VISITOR 11 | 12 | feature -- Visitor Pattern 13 | 14 | visit_json_array (a_json_array: JSON_ARRAY) 15 | -- Visit `a_json_array'. 16 | require 17 | a_json_array_not_void: a_json_array /= Void 18 | deferred 19 | end 20 | 21 | visit_json_boolean (a_json_boolean: JSON_BOOLEAN) 22 | -- Visit `a_json_boolean'. 23 | require 24 | a_json_boolean_not_void: a_json_boolean /= Void 25 | deferred 26 | end 27 | 28 | visit_json_null (a_json_null: JSON_NULL) 29 | -- Visit `a_json_null'. 30 | require 31 | a_json_null_not_void: a_json_null /= Void 32 | deferred 33 | end 34 | 35 | visit_json_number (a_json_number: JSON_NUMBER) 36 | -- Visit `a_json_number'. 37 | require 38 | a_json_number_not_void: a_json_number /= Void 39 | deferred 40 | end 41 | 42 | visit_json_object (a_json_object: JSON_OBJECT) 43 | -- Visit `a_json_object'. 44 | require 45 | a_json_object_not_void: a_json_object /= Void 46 | deferred 47 | end 48 | 49 | visit_json_string (a_json_string: JSON_STRING) 50 | -- Visit `a_json_string'. 51 | require 52 | a_json_string_not_void: a_json_string /= Void 53 | deferred 54 | end 55 | 56 | note 57 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 58 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 59 | end 60 | -------------------------------------------------------------------------------- /examples/serialization/custom/team_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEAM_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEAM_JSON_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | local 16 | j_object, j_dico: JSON_OBJECT 17 | j_array: JSON_ARRAY 18 | j_value: detachable JSON_VALUE 19 | i: INTEGER 20 | do 21 | if attached {TEAM} obj as grp then 22 | create j_object.make_with_capacity (2) 23 | -- "name" 24 | j_object.put_string (grp.name, "name") 25 | 26 | -- "owner" 27 | if attached grp.owner as p then 28 | ctx.on_field_start ("owner") 29 | j_value := ctx.to_json (p, Current) 30 | if j_value /= Void then 31 | j_object.put (j_value, "owner") 32 | else 33 | check type_serializable: False end 34 | end 35 | ctx.on_field_end ("owner") 36 | end 37 | 38 | -- "persons" 39 | if attached grp.persons as lst then 40 | ctx.on_field_start ("persons") 41 | create j_array.make (lst.count) 42 | across 43 | lst as ic 44 | loop 45 | j_value := ctx.to_json (ic.item, Current) 46 | if j_value = Void then 47 | check type_serializable: False end 48 | create {JSON_NULL} j_value 49 | end 50 | j_array.extend (j_value) 51 | end 52 | j_object.put (j_array, "persons") 53 | ctx.on_field_end ("persons") 54 | end 55 | Result := j_object 56 | else 57 | create {JSON_NULL} Result 58 | end 59 | end 60 | 61 | end 62 | -------------------------------------------------------------------------------- /library/serialization/serializer/json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON serializer." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | deferred class 7 | JSON_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZATION_I 11 | 12 | feature -- Conversion 13 | 14 | append_to_json_string (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT; a_json_string: STRING_GENERAL) 15 | -- Append JSON serialization of Eiffel value `obj' into `a_json_string', in the eventual context `ctx'. 16 | require 17 | is_accepted: ctx.is_accepted_object (obj) 18 | local 19 | vis: JSON_VISITOR 20 | j_value: like to_json 21 | do 22 | j_value := to_json (obj, ctx) 23 | if ctx.is_pretty_printing then 24 | create {JSON_PRETTY_STRING_VISITOR} vis.make (a_json_string) 25 | else 26 | create {JSON_SERIALIZATION_VISITOR} vis.make (a_json_string) 27 | end 28 | j_value.accept (vis) 29 | end 30 | 31 | to_json_string (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): STRING 32 | -- JSON serialization of Eiffel value `obj' as json string, in the eventual context `ctx'. 33 | require 34 | is_accepted: ctx.is_accepted_object (obj) 35 | do 36 | create Result.make (0) 37 | append_to_json_string (obj, ctx, Result) 38 | end 39 | 40 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 41 | -- JSON value representing the JSON serialization of Eiffel value `obj', in the eventual context `ctx'. 42 | require 43 | is_accepted: ctx.is_accepted_object (obj) 44 | deferred 45 | end 46 | 47 | note 48 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 49 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 50 | end 51 | -------------------------------------------------------------------------------- /test/autotest/test_suite/data/pass1.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "0123456789": "digit", 27 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 28 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 29 | "true": true, 30 | "false": false, 31 | "null": null, 32 | "array":[ ], 33 | "object":{ }, 34 | "address": "50 St. James Street", 35 | "url": "http://www.JSON.org/", 36 | "comment": "// /* */": " ", 38 | " s p a c e d " :[1,2 , 3 39 | 40 | , 41 | 42 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066, 54 | 1e1, 55 | 0.1e1, 56 | 1e-1, 57 | 1e00,2e+00,2e-00 58 | ,"rosebud"] -------------------------------------------------------------------------------- /library/converter/json_list_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for LIST [ANY]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | deferred class 9 | JSON_LIST_CONVERTER 10 | 11 | obsolete 12 | "This JSON converter design has issues [Sept/2014]." 13 | 14 | inherit 15 | 16 | JSON_CONVERTER 17 | 18 | feature {NONE} -- Initialization 19 | 20 | make 21 | do 22 | object := new_object (0) 23 | end 24 | 25 | feature -- Access 26 | 27 | object: LIST [detachable ANY] 28 | 29 | feature {NONE} -- Factory 30 | 31 | new_object (nb: INTEGER): like object 32 | deferred 33 | ensure 34 | Result /= Void 35 | end 36 | 37 | feature -- Conversion 38 | 39 | from_json (j: attached like to_json): detachable like object 40 | local 41 | i: INTEGER 42 | do 43 | Result := new_object (j.count) 44 | from 45 | i := 1 46 | until 47 | i > j.count 48 | loop 49 | Result.extend (json.object (j [i], Void)) 50 | i := i + 1 51 | end 52 | end 53 | 54 | to_json (o: like object): detachable JSON_ARRAY 55 | local 56 | c: ITERATION_CURSOR [detachable ANY] 57 | failed: BOOLEAN 58 | do 59 | create Result.make (o.count) 60 | from 61 | c := o.new_cursor 62 | until 63 | c.after 64 | loop 65 | if attached json.value (c.item) as jv then 66 | Result.add (jv) 67 | else 68 | failed := True 69 | end 70 | c.forth 71 | end 72 | if failed then 73 | Result := Void 74 | end 75 | end 76 | 77 | note 78 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 79 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 80 | end -- class JSON_ARRAYED_LIST_CONVERTER 81 | -------------------------------------------------------------------------------- /library/serialization/serializer/table_iterable_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TABLE_ITERABLE_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TABLE_ITERABLE_JSON_SERIALIZER [G -> detachable ANY, K -> READABLE_STRING_GENERAL] 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | -- JSON value representing the JSON serialization of Eiffel value `obj', in the eventual context `ctx'. 16 | local 17 | j_tb: JSON_OBJECT 18 | k: JSON_STRING 19 | do 20 | if attached {TABLE_ITERABLE [G, K]} obj as tb then 21 | -- Is this a good idea? 22 | -- what about object exporting an ITERABLE interface, 23 | -- but containing other attributes unrelated to that iterable nature! 24 | -- up to the dev to use or not this serializer! 25 | if attached {HASH_TABLE [G, K]} tb as htb then 26 | create j_tb.make_with_capacity (htb.count) 27 | else 28 | create j_tb.make_empty 29 | end 30 | across 31 | tb as ic 32 | loop 33 | ctx.on_field_start (ic.key) 34 | create k.make_from_string_general (ic.key) 35 | if 36 | attached ic.item as l_item and then 37 | attached ctx.to_json (l_item, Current) as j_value 38 | then 39 | j_tb.put (j_value, k) 40 | else 41 | j_tb.put (create {JSON_NULL}, k) 42 | end 43 | ctx.on_field_end (ic.key) 44 | end 45 | Result := j_tb 46 | else 47 | create {JSON_NULL} Result 48 | end 49 | end 50 | 51 | note 52 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 53 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 54 | end 55 | -------------------------------------------------------------------------------- /test/autotest/test_suite/test_obsolete_json.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEST_OBSOLETE_JSON}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | TEST_OBSOLETE_JSON 9 | 10 | inherit 11 | SHARED_EJSON 12 | undefine 13 | default_create 14 | end 15 | 16 | EQA_TEST_SET 17 | 18 | JSON_PARSER_ACCESS 19 | undefine 20 | default_create 21 | end 22 | 23 | EXCEPTIONS 24 | undefine 25 | default_create 26 | end 27 | 28 | feature -- Factory 29 | 30 | new_parser (a_string: STRING_8): JSON_PARSER 31 | do 32 | create Result.make_with_string (a_string) 33 | end 34 | 35 | feature -- Test 36 | 37 | test_json_failed_json_conversion 38 | -- Test converting an Eiffel object to JSON that is based on a class 39 | -- for which no JSON converter has been registered. 40 | local 41 | gv: OPERATING_ENVIRONMENT 42 | jv: detachable JSON_VALUE 43 | has_exception: BOOLEAN 44 | do 45 | if not has_exception then 46 | create gv 47 | jv := json.value (gv) 48 | else 49 | assert ("exceptions.is_developer_exception", is_developer_exception) 50 | end 51 | rescue 52 | has_exception := True 53 | retry 54 | end 55 | 56 | test_json_failed_eiffel_conversion 57 | -- Test converting from a JSON value to an Eiffel object based on a 58 | -- class for which no JSON converter has been registered. 59 | local 60 | gv: detachable ANY 61 | jo: JSON_OBJECT 62 | has_exception: BOOLEAN 63 | do 64 | if not has_exception then 65 | create jo.make 66 | gv := json.object (jo, "OPERATING_ENVIRONMENT") 67 | else 68 | assert ("exceptions.is_developer_exception", is_developer_exception) 69 | end 70 | rescue 71 | has_exception := True 72 | retry 73 | end 74 | 75 | end 76 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/json_book_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for BOOK" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_BOOK_CONVERTER 9 | 10 | inherit 11 | 12 | JSON_CONVERTER 13 | 14 | create 15 | make 16 | 17 | feature {NONE} -- Initialization 18 | 19 | make 20 | local 21 | ucs: STRING_32 22 | a: AUTHOR 23 | do 24 | create ucs.make_from_string ("") 25 | create a.make (ucs) 26 | create object.make (ucs, a, ucs) 27 | end 28 | 29 | feature -- Access 30 | 31 | object: BOOK 32 | 33 | feature -- Conversion 34 | 35 | from_json (j: like to_json): detachable like object 36 | do 37 | if 38 | attached {STRING_32} json.object (j.item (title_key), Void) as l_title and 39 | attached {STRING_32} json.object (j.item (isbn_key), Void) as l_isbn and 40 | attached {AUTHOR} json.object (j.item (author_key), "AUTHOR") as l_author 41 | then 42 | create Result.make (l_title, l_author, l_isbn) 43 | end 44 | end 45 | 46 | to_json (o: like object): JSON_OBJECT 47 | do 48 | create Result.make_with_capacity (3) 49 | Result.put (json.value (o.title), title_key) 50 | Result.put (json.value (o.isbn), isbn_key) 51 | Result.put (json.value (o.author), author_key) 52 | end 53 | 54 | feature {NONE} -- Implementation 55 | 56 | title_key: JSON_STRING 57 | -- Book's title label. 58 | once 59 | create Result.make_from_string ("title") 60 | end 61 | 62 | isbn_key: JSON_STRING 63 | -- Book ISBN label. 64 | once 65 | create Result.make_from_string ("isbn") 66 | end 67 | 68 | author_key: JSON_STRING 69 | -- Author label. 70 | once 71 | create Result.make_from_string ("author") 72 | end 73 | 74 | end -- class JSON_BOOK_CONVERTER 75 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/test_json_custom_classes.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Parsing and converter of book collection test." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEST_JSON_CUSTOM_CLASSES 8 | 9 | inherit 10 | 11 | SHARED_EJSON 12 | undefine 13 | default_create 14 | end 15 | 16 | EQA_TEST_SET 17 | 18 | feature -- Test 19 | 20 | test_custom_classes 21 | -- Parse JSON representation to JSON_OBJECT and test book collection converter. 22 | local 23 | jbc: JSON_BOOK_CONVERTER 24 | jbcc: JSON_BOOK_COLLECTION_CONVERTER 25 | jac: JSON_AUTHOR_CONVERTER 26 | parser: JSON_PARSER 27 | jrep: STRING 28 | do 29 | create jbc.make 30 | json.add_converter (jbc) 31 | create jbcc.make 32 | json.add_converter (jbcc) 33 | create jac.make 34 | json.add_converter (jac) 35 | jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}" 36 | create parser.make_with_string (jrep) 37 | parser.parse_content 38 | if parser.is_valid and then attached parser.parsed_json_object as l_json_object then 39 | if attached {BOOK_COLLECTION} json.object (l_json_object, "BOOK_COLLECTION") as l_collection then 40 | if attached {JSON_OBJECT} json.value (l_collection) as l_json_object_2 then 41 | assert ("JSON representation is correct", l_json_object_2.representation.same_string (jrep)) 42 | else 43 | assert ("BOOK_COLLECTION converted to JSON_OBJECT", False) 44 | end 45 | else 46 | assert ("JSON_OBJECT converted to BOOK_COLLECTION", False) 47 | end 48 | else 49 | assert ("JSON object representation to JSON_OBJECT", False) 50 | end 51 | end 52 | 53 | end -- class TEST_JSON_CUSTOM_CLASS 54 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/test_obsolete_json.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEST_OBSOLETE_JSON}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | TEST_OBSOLETE_JSON 9 | 10 | inherit 11 | SHARED_EJSON 12 | undefine 13 | default_create 14 | end 15 | 16 | EQA_TEST_SET 17 | 18 | JSON_PARSER_ACCESS 19 | undefine 20 | default_create 21 | end 22 | 23 | EXCEPTIONS 24 | undefine 25 | default_create 26 | end 27 | 28 | feature -- Factory 29 | 30 | new_parser (a_string: STRING_8): JSON_PARSER 31 | do 32 | create Result.make_with_string (a_string) 33 | end 34 | 35 | feature -- Test 36 | 37 | test_json_failed_json_conversion 38 | -- Test converting an Eiffel object to JSON that is based on a class 39 | -- for which no JSON converter has been registered. 40 | local 41 | gv: OPERATING_ENVIRONMENT 42 | jv: detachable JSON_VALUE 43 | has_exception: BOOLEAN 44 | do 45 | if not has_exception then 46 | create gv 47 | jv := json.value (gv) 48 | else 49 | assert ("exceptions.is_developer_exception", is_developer_exception) 50 | end 51 | rescue 52 | has_exception := True 53 | retry 54 | end 55 | 56 | test_json_failed_eiffel_conversion 57 | -- Test converting from a JSON value to an Eiffel object based on a 58 | -- class for which no JSON converter has been registered. 59 | local 60 | gv: detachable ANY 61 | jo: JSON_OBJECT 62 | has_exception: BOOLEAN 63 | do 64 | if not has_exception then 65 | create jo.make 66 | gv := json.object (jo, "OPERATING_ENVIRONMENT") 67 | else 68 | assert ("exceptions.is_developer_exception", is_developer_exception) 69 | end 70 | rescue 71 | has_exception := True 72 | retry 73 | end 74 | 75 | end 76 | -------------------------------------------------------------------------------- /library/gobo_converter/converters/json_ds_linked_list_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for DS_LINKED_LIST [ANY]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | class JSON_DS_LINKED_LIST_CONVERTER 9 | 10 | inherit 11 | JSON_CONVERTER 12 | 13 | create 14 | make 15 | 16 | feature {NONE} -- Initialization 17 | 18 | make 19 | do 20 | create object.make 21 | end 22 | 23 | feature -- Access 24 | 25 | object: DS_LINKED_LIST [ANY] 26 | 27 | feature -- Conversion 28 | 29 | from_json (j: JSON_ARRAY): detachable like object 30 | local 31 | i: INTEGER 32 | do 33 | create Result.make 34 | from 35 | i := 1 36 | until 37 | i > j.count 38 | loop 39 | if attached json.object (j [i], Void) as o then 40 | Result.put_last (o) 41 | end 42 | i := i + 1 43 | end 44 | end 45 | 46 | to_json (o: like object): JSON_ARRAY 47 | local 48 | c: DS_LIST_CURSOR [ANY] 49 | do 50 | create Result.make_empty 51 | from 52 | c := o.new_cursor 53 | c.start 54 | until 55 | c.after 56 | loop 57 | if attached json.value (c.item) as v then 58 | Result.add (v) 59 | end 60 | c.forth 61 | end 62 | end 63 | 64 | note 65 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 66 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 67 | end -- class JSON_DS_LINKED_LIST_CONVERTER 68 | -------------------------------------------------------------------------------- /library/kernel/json_boolean.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Boolean values" 3 | author: "$Author$" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_BOOLEAN 9 | 10 | inherit 11 | 12 | JSON_VALUE 13 | 14 | create 15 | make, 16 | make_true, make_false, 17 | make_boolean 18 | 19 | feature {NONE} -- Initialization 20 | 21 | make (a_value: BOOLEAN) 22 | -- Initialize Current JSON boolean with `a_boolean'. 23 | do 24 | item := a_value 25 | end 26 | 27 | make_true 28 | -- Initialize Current JSON boolean with True. 29 | do 30 | make (True) 31 | end 32 | 33 | make_false 34 | -- Initialize Current JSON boolean with False. 35 | do 36 | make (False) 37 | end 38 | 39 | make_boolean (a_item: BOOLEAN) 40 | -- Initialize. 41 | obsolete 42 | "Use `make' [2017-05-31]" 43 | do 44 | make (a_item) 45 | end 46 | 47 | feature -- Access 48 | 49 | item: BOOLEAN 50 | -- Content 51 | 52 | hash_code: INTEGER 53 | -- Hash code value 54 | do 55 | Result := item.hash_code 56 | end 57 | 58 | representation: STRING 59 | do 60 | if item then 61 | Result := "true" 62 | else 63 | Result := "false" 64 | end 65 | end 66 | 67 | feature -- Visitor pattern 68 | 69 | accept (a_visitor: JSON_VISITOR) 70 | -- Accept `a_visitor'. 71 | -- (Call `visit_json_boolean' procedure on `a_visitor'.) 72 | do 73 | a_visitor.visit_json_boolean (Current) 74 | end 75 | 76 | feature -- Status report 77 | 78 | debug_output: STRING 79 | -- String that should be displayed in debugger to represent `Current'. 80 | do 81 | Result := item.out 82 | end 83 | 84 | note 85 | copyright: "2010-2017, Javier Velilla and others https://github.com/eiffelhub/json." 86 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 87 | end 88 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/person_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | PERSON_JSON_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | local 16 | j_object: JSON_OBJECT 17 | j_array: JSON_ARRAY 18 | j_value: detachable JSON_VALUE 19 | i: INTEGER 20 | do 21 | if attached {PERSON} obj as per then 22 | create j_object.make_with_capacity (3) 23 | 24 | ctx.on_object_serialization_start (per) 25 | -- "first_name" 26 | j_object.put_string (per.first_name, "first_name") 27 | -- "last_name" 28 | j_object.put_string (per.last_name, "last_name") 29 | 30 | -- "details" 31 | if attached per.details as d then 32 | ctx.on_field_start ("details") 33 | j_value := ctx.to_json (d, Current) 34 | if j_value = Void then 35 | check type_serializable: False end 36 | j_value := create {JSON_NULL} 37 | end 38 | j_object.put (j_value, "details") 39 | ctx.on_field_end ("details") 40 | end 41 | -- "co_workers" 42 | 43 | create j_array.make_empty 44 | i := 1 45 | across 46 | per.co_workers as ic 47 | loop 48 | ctx.on_field_start (i.out) 49 | j_value := ctx.to_json (ic.item, Current) 50 | if j_value = Void then 51 | check type_serializable: False end 52 | j_value := create {JSON_NULL} 53 | end 54 | j_array.extend (j_value) 55 | ctx.on_field_end (i.out) 56 | i := i + 1 57 | end 58 | j_object.put (j_array, "co_workers") 59 | Result := j_object 60 | ctx.on_object_serialization_end (j_object, per) 61 | else 62 | create {JSON_NULL} Result 63 | end 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /library/serialization/deserializer/support/list_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {LIST_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | LIST_JSON_DESERIALIZER [G -> detachable ANY] 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | JSON_TYPE_UTILITIES 14 | 15 | feature -- Conversion 16 | 17 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable LIST [G] 18 | -- Eiffel value deserialized from `a_json' value, in the eventual context `ctx'. 19 | local 20 | inf: JSON_DESERIALIZER_CREATION_INFORMATION 21 | l_item_type: detachable TYPE [detachable ANY] 22 | do 23 | if attached {JSON_ARRAY} a_json as j_array then 24 | create inf.make (a_type, a_json) 25 | ctx.on_value_creation (inf) 26 | if attached {like from_json} inf.object as lst then 27 | Result := lst 28 | elseif a_type = Void then 29 | ctx.on_value_skipped (j_array, a_type, "Could not instantiate from array data.") 30 | else 31 | ctx.on_value_skipped (j_array, a_type, "Could not instantiate {" + a_type.name + "} from array data.") 32 | end 33 | if Result /= Void and not ctx.has_error then 34 | if a_type /= Void and then a_type.generic_parameter_count = 1 then 35 | l_item_type := a_type.generic_parameter_type (1) 36 | end 37 | if l_item_type = Void then 38 | l_item_type := {G} 39 | end 40 | across 41 | j_array as ic 42 | loop 43 | if attached {G} ctx.value_from_json (ic.item, l_item_type) as g then 44 | Result.force (g) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | 51 | note 52 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 53 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 54 | end 55 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/model/book_collection.e: -------------------------------------------------------------------------------- 1 | class 2 | BOOK_COLLECTION 3 | 4 | create 5 | make 6 | 7 | feature {NONE} -- Initialization 8 | 9 | make (a_name: STRING_32) 10 | -- Create a book collection with `a_name' as `name'. 11 | do 12 | set_name (a_name) 13 | create book_index.make (10) 14 | ensure 15 | name_set: name = a_name 16 | end 17 | 18 | feature -- Access 19 | 20 | name: STRING_32 21 | -- Name. 22 | 23 | books: LIST [BOOK] 24 | -- collection of book. 25 | do 26 | create {LINKED_LIST [BOOK]} Result.make 27 | across 28 | book_index as it 29 | loop 30 | Result.append (it.item) 31 | end 32 | end 33 | 34 | books_by_author (a_author: STRING_32): LIST [BOOK] 35 | -- Books wrote by `a_author' in this collection. 36 | do 37 | if attached book_index [a_author] as l_result then 38 | Result := l_result 39 | else 40 | create {LINKED_LIST [BOOK]} Result.make 41 | end 42 | end 43 | 44 | feature -- Change 45 | 46 | set_name (a_name: STRING_32) 47 | -- Set `name' with `a_name'. 48 | do 49 | name := a_name 50 | ensure 51 | name_set: name = a_name 52 | end 53 | 54 | add_book (a_book: BOOK) 55 | -- Extend collection with `a_book'. 56 | local 57 | l: detachable LIST [BOOK] 58 | do 59 | l := book_index.at (a_book.author.name) 60 | if l = Void then 61 | create {LINKED_LIST [BOOK]} l.make 62 | book_index.put (l, a_book.author.name) 63 | end 64 | l.force (a_book) 65 | end 66 | 67 | add_books (book_list: like books) 68 | -- Append collection with `book_list'. 69 | do 70 | across 71 | book_list as it 72 | loop 73 | add_book (it.item) 74 | end 75 | end 76 | 77 | feature {NONE} -- Implementation 78 | 79 | book_index: HASH_TABLE [LIST [BOOK], STRING_32] 80 | -- Association of author name and its books. 81 | 82 | end -- class BOOK_COLLECTION 83 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/converter/json_book_collection_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for BOOK_COLLECTION" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_BOOK_COLLECTION_CONVERTER 9 | 10 | inherit 11 | 12 | JSON_CONVERTER 13 | 14 | create 15 | make 16 | 17 | feature {NONE} -- Initialization 18 | 19 | make 20 | local 21 | ucs: STRING_32 22 | do 23 | create ucs.make_from_string ("") 24 | create object.make (ucs) 25 | end 26 | 27 | feature -- Access 28 | 29 | object: BOOK_COLLECTION 30 | 31 | feature -- Conversion 32 | 33 | from_json (j: like to_json): detachable like object 34 | local 35 | l_books: LINKED_LIST [BOOK] 36 | do 37 | if 38 | attached {STRING_32} json.object (j.item (name_key), Void) as l_name and 39 | attached {JSON_ARRAY} j.item (books_key) as l_json_array 40 | then 41 | create Result.make (l_name) 42 | create l_books.make 43 | across 44 | l_json_array as it 45 | until 46 | Result = Void 47 | loop 48 | if attached {BOOK} json.object (it.item, "BOOK") as l_book then 49 | l_books.extend (l_book) 50 | else 51 | Result := Void 52 | -- Failed 53 | end 54 | end 55 | if Result /= Void then 56 | Result.add_books (l_books) 57 | end 58 | end 59 | end 60 | 61 | to_json (o: like object): JSON_OBJECT 62 | do 63 | create Result.make_with_capacity (2) 64 | Result.put (json.value (o.name), name_key) 65 | Result.put (json.value (o.books), books_key) 66 | end 67 | 68 | feature {NONE} -- Implementation 69 | 70 | name_key: JSON_STRING 71 | -- Collection's name label. 72 | once 73 | create Result.make_from_string ("name") 74 | end 75 | 76 | books_key: JSON_STRING 77 | -- Book list label. 78 | once 79 | create Result.make_from_string ("books") 80 | end 81 | 82 | end -- class JSON_BOOK_COLLECTION_CONVERTER 83 | -------------------------------------------------------------------------------- /library/serialization/deserializer/support/table_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TABLE_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | TABLE_JSON_DESERIALIZER [G -> detachable ANY] 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | JSON_TYPE_UTILITIES 14 | 15 | feature -- Conversion 16 | 17 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable TABLE [G, READABLE_STRING_GENERAL] 18 | -- Eiffel value deserialized from `a_json' value, in the eventual context `ctx'. 19 | local 20 | inf: JSON_DESERIALIZER_CREATION_INFORMATION 21 | l_item_type: detachable TYPE [detachable ANY] 22 | do 23 | if attached {JSON_OBJECT} a_json as j_table then 24 | create inf.make (a_type, a_json) 25 | ctx.on_value_creation (inf) 26 | if attached {like from_json} inf.object as tb then 27 | Result := tb 28 | elseif a_type = Void then 29 | ctx.on_value_skipped (j_table, a_type, "Could not instantiate from table data.") 30 | else 31 | ctx.on_value_skipped (j_table, a_type, "Could not instantiate {" + a_type.name + "} from table data.") 32 | end 33 | if Result /= Void and not ctx.has_error then 34 | if a_type /= Void and then a_type.generic_parameter_count >= 1 then 35 | l_item_type := a_type.generic_parameter_type (1) 36 | end 37 | if l_item_type = Void then 38 | l_item_type := {G} 39 | end 40 | across 41 | j_table as ic 42 | loop 43 | if attached {G} ctx.value_from_json (ic.item, l_item_type) as g then 44 | Result.force (g, ic.key.unescaped_string_32) 45 | end 46 | end 47 | end 48 | end 49 | end 50 | 51 | note 52 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 53 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 54 | end 55 | -------------------------------------------------------------------------------- /library/serialization/deserializer/support/array_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {ARRAY_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | ARRAY_JSON_DESERIALIZER [G -> detachable ANY] 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | JSON_TYPE_UTILITIES 14 | 15 | feature -- Conversion 16 | 17 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable ARRAY [G] 18 | -- Eiffel value deserialized from `a_json' value, in the eventual context `ctx'. 19 | local 20 | inf: JSON_DESERIALIZER_CREATION_INFORMATION 21 | l_item_type: detachable TYPE [detachable ANY] 22 | i: INTEGER 23 | do 24 | if attached {JSON_ARRAY} a_json as j_array then 25 | create inf.make (a_type, a_json) 26 | ctx.on_value_creation (inf) 27 | if attached {like from_json} inf.object as lst then 28 | Result := lst 29 | elseif a_type = Void then 30 | ctx.on_value_skipped (j_array, a_type, "Could not instantiate array object.") 31 | else 32 | ctx.on_value_skipped (j_array, a_type, "Could not instantiate array {" + a_type.name + "}.") 33 | end 34 | if Result /= Void and not ctx.has_error then 35 | if a_type /= Void and then a_type.generic_parameter_count = 1 then 36 | l_item_type := a_type.generic_parameter_type (1) 37 | end 38 | if l_item_type = Void then 39 | l_item_type := {G} 40 | end 41 | i := Result.lower 42 | across 43 | j_array as ic 44 | loop 45 | if attached {G} ctx.value_from_json (ic.item, l_item_type) as g then 46 | Result.force (g, i) 47 | i := i + 1 48 | end 49 | end 50 | end 51 | end 52 | end 53 | 54 | note 55 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 56 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 57 | end 58 | -------------------------------------------------------------------------------- /examples/serialization/custom/person_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | PERSON_JSON_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | local 16 | j_object: JSON_OBJECT 17 | j_array: JSON_ARRAY 18 | j_value: detachable JSON_VALUE 19 | i: INTEGER 20 | do 21 | if attached {PERSON} obj as per then 22 | create j_object.make_with_capacity (3) 23 | 24 | ctx.on_object_serialization_start (per) 25 | -- "first_name" 26 | j_object.put_string (per.first_name, "first_name") 27 | -- "last_name" 28 | j_object.put_string (per.last_name, "last_name") 29 | 30 | -- "details" 31 | if attached per.details as d then 32 | ctx.on_field_start ("details") 33 | j_value := ctx.to_json (d, Current) 34 | if j_value = Void then 35 | check type_serializable: False end 36 | j_value := create {JSON_NULL} 37 | end 38 | j_object.put (j_value, "details") 39 | ctx.on_field_end ("details") 40 | end 41 | -- "co_workers" 42 | if attached per.co_workers as l_co_workers and then not l_co_workers.is_empty then 43 | create j_array.make_empty 44 | i := 1 45 | across 46 | l_co_workers as ic 47 | loop 48 | ctx.on_field_start (i.out) 49 | j_value := ctx.to_json (ic.item, Current) 50 | if j_value = Void then 51 | check type_serializable: False end 52 | j_value := create {JSON_NULL} 53 | end 54 | j_array.extend (j_value) 55 | ctx.on_field_end (i.out) 56 | i := i + 1 57 | end 58 | j_object.put (j_array, "co_workers") 59 | end 60 | 61 | Result := j_object 62 | ctx.on_object_serialization_end (j_object, per) 63 | else 64 | create {JSON_NULL} Result 65 | end 66 | end 67 | 68 | end 69 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/team_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {APP_GROUP_FROM_JSON_CONVERTER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | TEAM_JSON_DESERIALIZER 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable TEAM 16 | do 17 | if attached {JSON_OBJECT} a_json as j_team then 18 | if 19 | attached {JSON_STRING} j_team.item ("name") as j_name 20 | then 21 | create Result.make (j_name.unescaped_string_32) 22 | if attached {JSON_OBJECT} j_team.item ("owner") as j_owner then 23 | if attached {PERSON} ctx.value_from_json (a_json, {PERSON}) as p then 24 | Result.set_owner (p) 25 | end 26 | end 27 | if attached {JSON_ARRAY} j_team.item ("persons") as j_persons then 28 | if attached ctx.deserializer ({PERSON}) as conv then 29 | across 30 | j_persons as ic 31 | loop 32 | if attached {PERSON} ctx.value_from_json (ic.item, {PERSON}) as l_person then 33 | Result.put (l_person) 34 | end 35 | end 36 | end 37 | end 38 | if attached {JSON_ARRAY} j_team.item ("vectors") as j_vectors then 39 | Result.vectors.wipe_out 40 | across 41 | j_vectors as ic 42 | loop 43 | if attached {JSON_STRING} ic.item as j_string then 44 | Result.add_vector (j_string.item) 45 | end 46 | end 47 | end 48 | 49 | if attached {JSON_OBJECT} j_team.item ("dico") as j_dico then 50 | Result.dico.wipe_out 51 | across 52 | j_dico as ic 53 | loop 54 | if attached {JSON_STRING} ic.item as j_string then 55 | Result.dico.force (j_string.unescaped_string_32, ic.key.unescaped_string_32) 56 | end 57 | end 58 | end 59 | end 60 | end 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /library/converter/json_hash_table_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | class 9 | JSON_HASH_TABLE_CONVERTER 10 | 11 | obsolete 12 | "This JSON converter design has issues [Sept/2014]." 13 | 14 | inherit 15 | 16 | JSON_CONVERTER 17 | 18 | create 19 | make 20 | 21 | feature {NONE} -- Initialization 22 | 23 | make 24 | do 25 | create object.make (0) 26 | end 27 | 28 | feature -- Access 29 | 30 | object: HASH_TABLE [ANY, HASHABLE] 31 | 32 | feature -- Conversion 33 | 34 | from_json (j: attached like to_json): like object 35 | do 36 | create Result.make (j.count) 37 | across 38 | j as ic 39 | loop 40 | if attached json.object (ic.item, Void) as l_object then 41 | if attached {HASHABLE} json.object (ic.key, Void) as h then 42 | Result.put (l_object, h) 43 | else 44 | check 45 | key_is_hashable: False 46 | end 47 | end 48 | else 49 | check 50 | object_attached: False 51 | end 52 | end 53 | end 54 | end 55 | 56 | to_json (o: like object): detachable JSON_OBJECT 57 | local 58 | js: JSON_STRING 59 | failed: BOOLEAN 60 | do 61 | create Result.make 62 | across 63 | o as c 64 | loop 65 | if attached {JSON_STRING} json.value (c.key) as l_key then 66 | js := l_key 67 | else 68 | if attached {READABLE_STRING_GENERAL} c.key as s_key then 69 | create js.make_from_string_general (s_key) 70 | else 71 | create js.make_from_string (c.key.out) 72 | end 73 | end 74 | if attached json.value (c.item) as jv then 75 | Result.put (jv, js) 76 | else 77 | failed := True 78 | end 79 | end 80 | if failed then 81 | Result := Void 82 | end 83 | end 84 | 85 | note 86 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 87 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 88 | end -- class JSON_HASH_TABLE_CONVERTER 89 | -------------------------------------------------------------------------------- /test/autotest/test_suite/test_ds.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Linked list and hash table converters test." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEST_DS 8 | 9 | inherit 10 | 11 | SHARED_EJSON 12 | undefine 13 | default_create 14 | end 15 | 16 | EQA_TEST_SET 17 | 18 | feature -- Test 19 | 20 | test_linked_list_converter 21 | -- Convert a linked list to a json value and 22 | -- convert this one to a linked list. 23 | local 24 | l: LINKED_LIST [STRING] 25 | s: STRING 26 | do 27 | create l.make 28 | l.force ("foo") 29 | l.force ("bar") 30 | if attached json.value (l) as l_value then 31 | s := l_value.representation 32 | assert ("JSON array converted to LINKED_LIST", attached {LINKED_LIST [detachable ANY]} json.object (l_value, "LINKED_LIST")) 33 | else 34 | assert ("LINKED_LIST converted to a JSON value", False) 35 | end 36 | end 37 | 38 | test_hash_table_converter 39 | -- Convert a hash table to a json value and 40 | -- convert this one to a hash table. 41 | local 42 | t: HASH_TABLE [STRING, STRING] 43 | s: STRING 44 | l_ucs_key: detachable STRING_32 45 | do 46 | create t.make (2) 47 | t.put ("foo", "1") 48 | t.put ("bar", "2") 49 | if attached json.value (t) as l_value then 50 | s := l_value.representation 51 | if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then 52 | create l_ucs_key.make_from_string ("1") 53 | if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then 54 | assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.same_string_general ("foo")) 55 | else 56 | assert ("ucs_value /= Void", False) 57 | end 58 | create l_ucs_key.make_from_string ("2") 59 | if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then 60 | assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.same_string_general ("bar")) 61 | else 62 | assert ("ucs_value /= Void", False) 63 | end 64 | else 65 | assert ("JSON object converted to HASH_TABLE", False); 66 | end 67 | else 68 | assert ("HASH_TABLE converted to a JSON value", False) 69 | end 70 | end 71 | 72 | end -- class TEST_DS 73 | -------------------------------------------------------------------------------- /test/autotest/test_suite/obsolete/test_ds.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Linked list and hash table converters test." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEST_DS 8 | 9 | inherit 10 | 11 | SHARED_EJSON 12 | undefine 13 | default_create 14 | end 15 | 16 | EQA_TEST_SET 17 | 18 | feature -- Test 19 | 20 | test_linked_list_converter 21 | -- Convert a linked list to a json value and 22 | -- convert this one to a linked list. 23 | local 24 | l: LINKED_LIST [STRING] 25 | s: STRING 26 | do 27 | create l.make 28 | l.force ("foo") 29 | l.force ("bar") 30 | if attached json.value (l) as l_value then 31 | s := l_value.representation 32 | assert ("JSON array converted to LINKED_LIST", attached {LINKED_LIST [detachable ANY]} json.object (l_value, "LINKED_LIST")) 33 | else 34 | assert ("LINKED_LIST converted to a JSON value", False) 35 | end 36 | end 37 | 38 | test_hash_table_converter 39 | -- Convert a hash table to a json value and 40 | -- convert this one to a hash table. 41 | local 42 | t: HASH_TABLE [STRING, STRING] 43 | s: STRING 44 | l_ucs_key: detachable STRING_32 45 | do 46 | create t.make (2) 47 | t.put ("foo", "1") 48 | t.put ("bar", "2") 49 | if attached json.value (t) as l_value then 50 | s := l_value.representation 51 | if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then 52 | create l_ucs_key.make_from_string ("1") 53 | if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then 54 | assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.same_string_general ("foo")) 55 | else 56 | assert ("ucs_value /= Void", False) 57 | end 58 | create l_ucs_key.make_from_string ("2") 59 | if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then 60 | assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.same_string_general ("bar")) 61 | else 62 | assert ("ucs_value /= Void", False) 63 | end 64 | else 65 | assert ("JSON object converted to HASH_TABLE", False); 66 | end 67 | else 68 | assert ("HASH_TABLE converted to a JSON value", False) 69 | end 70 | end 71 | 72 | end -- class TEST_DS 73 | -------------------------------------------------------------------------------- /examples/serialization/custom/person_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_JSON_DESERIALIZER 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable PERSON 16 | local 17 | -- p_conv, t_conv: detachable JSON_DESERIALIZER 18 | do 19 | if attached {JSON_OBJECT} a_json as j_person then 20 | if 21 | attached {JSON_STRING} j_person.item ("first_name") as j_first_name and 22 | attached {JSON_STRING} j_person.item ("last_name") as j_last_name 23 | then 24 | create Result.make (j_first_name.unescaped_string_32, j_last_name.unescaped_string_32) 25 | 26 | if attached {JSON_OBJECT} j_person.item ("details") as j_details then 27 | if attached {PERSON_DETAILS} ctx.value_from_json (j_details, {PERSON_DETAILS}) as l_details then 28 | Result.set_details (l_details) 29 | end 30 | -- if attached ctx.deserializer ({PERSON_DETAILS}) as conv then 31 | -- if attached {PERSON_DETAILS} conv.from_json (j_details, ctx, {PERSON_DETAILS}) as l_details then 32 | -- Result.set_details (l_details) 33 | -- end 34 | -- end 35 | end 36 | if attached {JSON_ARRAY} j_person.item ("co_workers") as j_coworkers then 37 | -- p_conv := ctx.deserializer ({PERSON}) 38 | -- t_conv := ctx.deserializer ({TEAM}) 39 | across 40 | j_coworkers as ic 41 | loop 42 | if attached {ENTITY} ctx.value_from_json (ic.item, {PERSON}) as p then 43 | Result.add_co_worker (p) 44 | elseif attached {ENTITY} ctx.value_from_json (ic.item, {TEAM}) as t then 45 | Result.add_co_worker (t) 46 | end 47 | -- if p_conv /= Void and then attached {ENTITY} p_conv.from_json (ic.item, ctx, {PERSON}) as e then 48 | -- Result.add_co_worker (e) 49 | -- elseif t_conv /= Void and then attached {ENTITY} t_conv.from_json (ic.item, ctx, {TEAM}) as e then 50 | -- Result.add_co_worker (e) 51 | -- end 52 | end 53 | end 54 | end 55 | end 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/person_json_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {PERSON_JSON_DESERIALIZER}." 3 | author: "" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | PERSON_JSON_DESERIALIZER 9 | 10 | inherit 11 | JSON_DESERIALIZER 12 | 13 | feature -- Conversion 14 | 15 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable PERSON 16 | local 17 | -- p_conv, t_conv: detachable JSON_DESERIALIZER 18 | do 19 | if attached {JSON_OBJECT} a_json as j_person then 20 | if 21 | attached {JSON_STRING} j_person.item ("first_name") as j_first_name and 22 | attached {JSON_STRING} j_person.item ("last_name") as j_last_name 23 | then 24 | create Result.make (j_first_name.unescaped_string_32, j_last_name.unescaped_string_32) 25 | 26 | if attached {JSON_OBJECT} j_person.item ("details") as j_details then 27 | if attached {PERSON_DETAILS} ctx.value_from_json (j_details, {PERSON_DETAILS}) as l_details then 28 | Result.set_details (l_details) 29 | end 30 | -- if attached ctx.deserializer ({PERSON_DETAILS}) as conv then 31 | -- if attached {PERSON_DETAILS} conv.from_json (j_details, ctx, {PERSON_DETAILS}) as l_details then 32 | -- Result.set_details (l_details) 33 | -- end 34 | -- end 35 | end 36 | if attached {JSON_ARRAY} j_person.item ("co_workers") as j_coworkers then 37 | -- p_conv := ctx.deserializer ({PERSON}) 38 | -- t_conv := ctx.deserializer ({TEAM}) 39 | across 40 | j_coworkers as ic 41 | loop 42 | if attached {ENTITY} ctx.value_from_json (ic.item, {PERSON}) as p then 43 | Result.add_co_worker (p) 44 | elseif attached {ENTITY} ctx.value_from_json (ic.item, {TEAM}) as t then 45 | Result.add_co_worker (t) 46 | end 47 | -- if p_conv /= Void and then attached {ENTITY} p_conv.from_json (ic.item, ctx, {PERSON}) as e then 48 | -- Result.add_co_worker (e) 49 | -- elseif t_conv /= Void and then attached {ENTITY} t_conv.from_json (ic.item, ctx, {TEAM}) as e then 50 | -- Result.add_co_worker (e) 51 | -- end 52 | end 53 | end 54 | end 55 | end 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /library/parser/json_tokens.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Token used by the JSON_PARSER" 3 | author: "$Author$" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | 7 | class 8 | JSON_TOKENS 9 | 10 | feature -- Access 11 | 12 | token_object_open: CHARACTER = '{' 13 | token_object_close: CHARACTER = '}' 14 | 15 | token_array_open: CHARACTER = '[' 16 | token_array_close: CHARACTER = ']' 17 | 18 | token_double_quote: CHARACTER = '"' 19 | token_plus: CHARACTER = '+' 20 | token_minus: CHARACTER = '-' 21 | token_dot: CHARACTER = '.' 22 | token_exp: CHARACTER = 'e' 23 | token_comma: CHARACTER = ',' 24 | token_colon: CHARACTER = ':' 25 | 26 | feature -- Status report 27 | 28 | is_open_token (c: CHARACTER): BOOLEAN 29 | -- Characters which open a type 30 | do 31 | inspect c 32 | when token_object_open, token_array_open, token_double_quote, token_plus, token_minus, token_dot then 33 | Result := True 34 | else 35 | 36 | end 37 | end 38 | 39 | is_close_token (c: CHARACTER): BOOLEAN 40 | -- Characters which close a type 41 | do 42 | inspect c 43 | when token_object_close, token_array_close, token_double_quote then 44 | Result := True 45 | else 46 | 47 | end 48 | end 49 | 50 | is_special_character (c: CHARACTER): BOOLEAN 51 | -- Control Characters 52 | -- %F Form feed 53 | -- %H backslasH 54 | -- %N Newline 55 | -- %R carriage Return 56 | -- %T horizontal Tab 57 | -- %B Backspace 58 | -- / Solidus 59 | -- " Quotation 60 | do 61 | inspect c 62 | when '"', '%H' , '/', '%B', '%F', '%N', '%R', '%T' then -- '%H' = '\' = reverse solidus 63 | Result := True 64 | else 65 | 66 | end 67 | end 68 | 69 | is_special_control (c: CHARACTER): BOOLEAN 70 | -- Control Characters 71 | -- \b\f\n\r\t 72 | do 73 | inspect c 74 | when 'b', 'f', 'n', 'r', 't' then 75 | Result := True 76 | else 77 | 78 | end 79 | end 80 | 81 | is_exp_token (c: CHARACTER): BOOLEAN 82 | -- Is number exposant token? 83 | do 84 | Result := c = token_exp or else c.as_lower = token_exp 85 | end 86 | 87 | note 88 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 89 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 90 | end 91 | -------------------------------------------------------------------------------- /examples/basic/basic.e: -------------------------------------------------------------------------------- 1 | class 2 | BASIC 3 | 4 | create 5 | make 6 | 7 | feature {NONE} -- Initialization 8 | 9 | make 10 | -- Initialize `Current'. 11 | local 12 | parser: JSON_PARSER 13 | printer: JSON_PRETTY_STRING_VISITOR 14 | s: STRING_32 15 | do 16 | -- Create parser for content `json_content' 17 | create parser.make_with_string (json_content) 18 | -- Parse the content 19 | parser.parse_content 20 | if 21 | parser.is_valid and then 22 | attached parser.parsed_json_value as jv 23 | then 24 | -- Json content is valid, and well parser. 25 | -- and the parsed json value is `jv' 26 | 27 | -- Let's access the glossary/title value 28 | if 29 | attached {JSON_OBJECT} jv as j_object and then 30 | attached {JSON_OBJECT} j_object.item ("glossary") as j_glossary and then 31 | attached {JSON_STRING} j_glossary.item ("title") as j_title 32 | then 33 | print ("The glossary title is %"" + j_title.unescaped_string_8 + "%".%N") 34 | else 35 | print ("The glossary title was not found!%N") 36 | end 37 | 38 | -- Pretty print the parsed JSON 39 | create s.make_empty 40 | create printer.make (s) 41 | jv.accept (printer) 42 | print ("The JSON formatted using a pretty printer:%N") 43 | print (s) 44 | else 45 | print("Error(s) occurred while parsing the json string:%N" + json_content + "%NError:" + parser.errors_as_string) 46 | end 47 | end 48 | 49 | feature -- Status 50 | 51 | feature -- Access 52 | 53 | json_content: STRING = "[ 54 | { 55 | "glossary": { 56 | "title": "example glossary", 57 | "GlossDiv": { 58 | "title": "S", 59 | "GlossList": { 60 | "GlossEntry": { 61 | "ID": "SGML", 62 | "SortAs": "SGML", 63 | "GlossTerm": "Standard Generalized Markup Language", 64 | "Acronym": "SGML", 65 | "Abbrev": "ISO 8879:1986", 66 | "GlossDef": { 67 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 68 | "GlossSeeAlso": ["GML", "XML"] 69 | }, 70 | "GlossSee": "markup" 71 | } 72 | } 73 | } 74 | } 75 | } 76 | ]" 77 | 78 | feature -- Change 79 | 80 | feature {NONE} -- Implementation 81 | 82 | invariant 83 | -- invariant_clause: True 84 | 85 | end 86 | -------------------------------------------------------------------------------- /examples/performance/basic.e: -------------------------------------------------------------------------------- 1 | class 2 | BASIC 3 | 4 | create 5 | make 6 | 7 | feature {NONE} -- Initialization 8 | 9 | make 10 | -- Initialize `Current'. 11 | local 12 | parser: JSON_PARSER 13 | l_stopwatch: DT_STOPWATCH 14 | i: INTEGER 15 | mem: MEMORY 16 | do 17 | create file_reader 18 | create mem 19 | -- Create parser for content `json_content' 20 | if attached json_file_from (file_name) as json_content then 21 | from 22 | i := 1 23 | until 24 | i > 10 25 | loop 26 | mem.collection_off 27 | create l_stopwatch.make 28 | l_stopwatch.start 29 | create parser.make_with_string (json_content) 30 | parser.set_default_array_size (25) 31 | parser.set_default_object_size (10) 32 | 33 | parser.parse_content 34 | if parser.is_parsed and then parser.is_valid and then not parser.has_error then 35 | debug 36 | print ("%NWas valid") 37 | end 38 | else 39 | debug 40 | print ("%NWas invalid") 41 | end 42 | end 43 | l_stopwatch.stop 44 | print ("%NElapsed time:" + l_stopwatch.elapsed_time.precise_time_out) 45 | parser.reset 46 | i := i + 1 47 | mem.full_coalesce 48 | mem.collection_on 49 | mem.full_collect 50 | end 51 | print ("%NPress Enter to exit!!!") 52 | io.read_line 53 | end 54 | end 55 | 56 | feature -- Status 57 | feature {NONE} -- Implementation 58 | 59 | file_name: STRING ="YOUR-FILE-NAME" 60 | 61 | file_reader: JSON_FILE_READER 62 | -- JSON file reader. 63 | 64 | json_file_from (fn: READABLE_STRING_GENERAL): detachable STRING 65 | local 66 | f: RAW_FILE 67 | l_path: PATH 68 | test_dir: PATH 69 | i: INTEGER 70 | do 71 | test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("data") 72 | l_path := test_dir.extended (fn) 73 | create f.make_with_path (l_path) 74 | if f.exists then 75 | -- Found json file 76 | else 77 | from 78 | i := 5 79 | until 80 | i = 0 81 | loop 82 | test_dir := test_dir.extended ("..") 83 | i := i - 1 84 | end 85 | l_path := test_dir.extended (fn) 86 | end 87 | create f.make_with_path (l_path) 88 | if f.exists then 89 | Result := file_reader.read_json_from (l_path.name) 90 | end 91 | check File_contains_json_data: Result /= Void end 92 | end 93 | invariant 94 | end 95 | -------------------------------------------------------------------------------- /examples/serialization/demo_basic_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Enter class description here! 4 | ]" 5 | 6 | class 7 | DEMO_BASIC_SERIALIZATION 8 | 9 | inherit 10 | OUTPUT_UTILITIES 11 | 12 | create 13 | make 14 | 15 | feature {NONE} -- Initialization 16 | 17 | make 18 | local 19 | conv: JSON_BASIC_SERIALIZATION 20 | json: STRING 21 | p: JSON_PARSER 22 | do 23 | print ("%N") 24 | print ("================================================%N") 25 | print ("= Serialization using only basic functionality =%N") 26 | print ("================================================%N") 27 | print ("%N") 28 | json := "[ 29 | { 30 | "name": "John", 31 | "city": "New York", 32 | "has_records": true, 33 | "records": [ 34 | { 35 | "id": 1, 36 | "city": "Los Angeles", 37 | "date": "2017" 38 | }, 39 | { 40 | "id": 2, 41 | "city": "San Francisco", 42 | "date": "2016", 43 | "notes": null 44 | }, 45 | { 46 | "id": 2, 47 | "city": "Santa Barbara", 48 | "date": "2015", 49 | "notes": ["a", "b", "c", { "line-1": 123, "line-2": "abc"} ] 50 | } 51 | ] 52 | } 53 | ]" 54 | 55 | -- Convert json to Eiffel objects, using STRING_TABLE, ARRAYED_LIST and basic types. 56 | create conv.make 57 | if attached conv.table_from_json_string (json) as tb then 58 | print ("%NConverted Table...%N") 59 | output_object (tb, "") 60 | 61 | conv.set_compact_printing 62 | print ("%NCompact serialization:%N") 63 | print (conv.to_json_string (tb)) 64 | print ("%NPretty serialization:%N") 65 | conv.set_pretty_printing 66 | print (conv.to_json_string (tb)) 67 | end 68 | 69 | -- Extract the "records" json array, to test the json array conversion to Eiffel. 70 | create p.make_with_string (json) 71 | p.parse_content 72 | if 73 | p.is_parsed and p.is_valid and then 74 | attached p.parsed_json_object as j_obj and then 75 | attached j_obj["records"] as j_records 76 | then 77 | print ("%NConverted array %"records%"...%N") 78 | print ("%N") 79 | if attached conv.list_from_json_string (j_records.representation) as lst then 80 | output_object (lst, "") 81 | conv.set_compact_printing 82 | print ("%NCompact serialization:%N") 83 | print (conv.to_json_string (lst)) 84 | print ("%NPretty serialization:%N") 85 | conv.set_pretty_printing 86 | print (conv.to_json_string (lst)) 87 | end 88 | end 89 | end 90 | 91 | end 92 | -------------------------------------------------------------------------------- /library/serialization/support/json_type_utilities.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Interface to access TYPE and run-time information 4 | ]" 5 | date: "$Date$" 6 | revision: "$Revision$" 7 | 8 | class 9 | JSON_TYPE_UTILITIES 10 | 11 | inherit 12 | REFLECTOR_CONSTANTS 13 | 14 | feature -- Access 15 | 16 | type_of_type (a_type_id: INTEGER): TYPE [detachable ANY] 17 | do 18 | Result := reflector.type_of_type (a_type_id) 19 | end 20 | 21 | is_deferred_type (a_type: TYPE [detachable ANY]): BOOLEAN 22 | do 23 | Result := a_type.is_deferred 24 | end 25 | 26 | feature -- Factory 27 | 28 | new_special_any_instance (a_type: TYPE [detachable ANY]; count: INTEGER): detachable SPECIAL [detachable ANY] 29 | do 30 | check reflector.is_special_type (a_type.type_id) end 31 | Result := reflector.new_special_any_instance (a_type.type_id, count) 32 | end 33 | 34 | new_instance_of (a_type_name: detachable READABLE_STRING_GENERAL; a_type: detachable TYPE [detachable ANY]): detachable ANY 35 | do 36 | if a_type_name /= Void then 37 | Result := new_instance_for_type_name (a_type_name) 38 | end 39 | if Result = Void and a_type /= Void then 40 | Result := new_instance_of_effective_type (a_type) 41 | end 42 | end 43 | 44 | new_instance_for_type_name (a_type_name: READABLE_STRING_GENERAL): detachable ANY 45 | do 46 | if 47 | attached reflector.dynamic_type_from_string (a_type_name) as l_type_id and then 48 | l_type_id >= 0 and then attached type_of_type (l_type_id) as l_type 49 | then 50 | Result := new_instance_of_effective_type (l_type) 51 | end 52 | end 53 | 54 | new_instance_of_effective_type (a_type: TYPE [detachable ANY]): detachable ANY 55 | do 56 | if a_type.has_default then 57 | Result := a_type.default 58 | end 59 | if Result = Void and then not is_deferred_type (a_type) then 60 | Result := new_instance_for_type_id (a_type.type_id) 61 | end 62 | end 63 | 64 | feature {NONE} -- Implementation 65 | 66 | new_instance_for_type_id (a_type_id: INTEGER): detachable ANY 67 | local 68 | l_retried: BOOLEAN 69 | do 70 | if a_type_id < 0 or l_retried then 71 | Result := Void 72 | else 73 | Result := reflector.new_instance_of (a_type_id) 74 | end 75 | rescue 76 | l_retried := True 77 | retry 78 | end 79 | 80 | feature {NONE} -- Implementation 81 | 82 | reflector: REFLECTOR 83 | once 84 | create Result 85 | end 86 | 87 | note 88 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 89 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 90 | end 91 | -------------------------------------------------------------------------------- /library/gobo_converter/converters/json_ds_hash_table_converter.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "A JSON converter for DS_HASH_TABLE [ANY, HASHABLE]" 3 | author: "Paul Cohen" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | file: "$HeadURL$" 7 | 8 | class JSON_DS_HASH_TABLE_CONVERTER 9 | 10 | inherit 11 | JSON_CONVERTER 12 | 13 | create 14 | make 15 | 16 | feature {NONE} -- Initialization 17 | 18 | make 19 | do 20 | create object.make (0) 21 | end 22 | 23 | feature -- Access 24 | 25 | object: DS_HASH_TABLE [ANY, HASHABLE] 26 | 27 | feature -- Conversion 28 | 29 | from_json (j: JSON_OBJECT): detachable like object 30 | local 31 | keys: ARRAY [JSON_STRING] 32 | i: INTEGER 33 | do 34 | keys := j.current_keys 35 | create Result.make (keys.count) 36 | from 37 | i := 1 38 | until 39 | i > keys.count 40 | loop 41 | if attached {HASHABLE} json.object (keys [i], void) as h then 42 | if attached json.object (j.item (keys [i]), Void) as o then 43 | Result.put (o, h) 44 | end 45 | else 46 | check key_hashable: False end 47 | end 48 | i := i + 1 49 | end 50 | end 51 | 52 | to_json (o: like object): detachable JSON_OBJECT 53 | local 54 | c: DS_HASH_TABLE_CURSOR [ANY, HASHABLE] 55 | js: JSON_STRING 56 | jv: JSON_VALUE 57 | failed: BOOLEAN 58 | do 59 | create Result.make 60 | from 61 | c := o.new_cursor 62 | c.start 63 | until 64 | c.after 65 | loop 66 | if attached {JSON_STRING} json.value (c.key) as l_key then 67 | js := l_key 68 | else 69 | create js.make_from_string_general (c.key.out) 70 | end 71 | jv := json.value (c.item) 72 | if jv /= Void then 73 | Result.put (jv, js) 74 | else 75 | failed := True 76 | end 77 | c.forth 78 | end 79 | if failed then 80 | Result := Void 81 | end 82 | end 83 | 84 | note 85 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 86 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 87 | end -- class JSON_DS_HASH_TABLE_CONVERTER 88 | -------------------------------------------------------------------------------- /library/utility/visitor/print_json_visitor.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE" 3 | author: "jvelilla" 4 | date: "$Date$" 5 | revision: "0.1" 6 | 7 | class 8 | PRINT_JSON_VISITOR 9 | 10 | inherit 11 | 12 | JSON_VISITOR 13 | 14 | create 15 | make 16 | 17 | feature -- Initialization 18 | 19 | make 20 | -- Create a new instance 21 | do 22 | create to_json.make_empty 23 | end 24 | 25 | feature -- Access 26 | 27 | to_json: STRING 28 | -- JSON representation 29 | 30 | feature -- Visitor Pattern 31 | 32 | visit_json_array (a_json_array: JSON_ARRAY) 33 | -- Visit `a_json_array'. 34 | local 35 | value: JSON_VALUE 36 | l_json_array: ARRAYED_LIST [JSON_VALUE] 37 | do 38 | l_json_array := a_json_array.array_representation 39 | to_json.append ("[") 40 | from 41 | l_json_array.start 42 | until 43 | l_json_array.off 44 | loop 45 | value := l_json_array.item 46 | value.accept (Current) 47 | l_json_array.forth 48 | if not l_json_array.after then 49 | to_json.append (",") 50 | end 51 | end 52 | to_json.append ("]") 53 | end 54 | 55 | visit_json_boolean (a_json_boolean: JSON_BOOLEAN) 56 | -- Visit `a_json_boolean'. 57 | do 58 | to_json.append (a_json_boolean.item.out) 59 | end 60 | 61 | visit_json_null (a_json_null: JSON_NULL) 62 | -- Visit `a_json_null'. 63 | do 64 | to_json.append ("null") 65 | end 66 | 67 | visit_json_number (a_json_number: JSON_NUMBER) 68 | -- Visit `a_json_number'. 69 | do 70 | to_json.append (a_json_number.item) 71 | end 72 | 73 | visit_json_object (a_json_object: JSON_OBJECT) 74 | -- Visit `a_json_object'. 75 | local 76 | l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING] 77 | do 78 | l_pairs := a_json_object.map_representation 79 | to_json.append ("{") 80 | from 81 | l_pairs.start 82 | until 83 | l_pairs.off 84 | loop 85 | l_pairs.key_for_iteration.accept (Current) 86 | to_json.append (":") 87 | l_pairs.item_for_iteration.accept (Current) 88 | l_pairs.forth 89 | if not l_pairs.after then 90 | to_json.append (",") 91 | end 92 | end 93 | to_json.append ("}") 94 | end 95 | 96 | visit_json_string (a_json_string: JSON_STRING) 97 | -- Visit `a_json_string'. 98 | do 99 | to_json.append ("%"") 100 | to_json.append (a_json_string.item) 101 | to_json.append ("%"") 102 | end 103 | 104 | note 105 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 106 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 107 | end 108 | -------------------------------------------------------------------------------- /library/kernel/json_value.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON_VALUE represents a value in JSON. 4 | A value can be 5 | * a string in double quotes 6 | * a number 7 | * boolean value (true, false) 8 | * null 9 | * an object 10 | * an array 11 | ]" 12 | date: "$Date$" 13 | revision: "$Revision$" 14 | license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" 15 | EIS: "name=Introducing JSON", "protocol=URI", "src=http://json.org/" 16 | 17 | deferred class 18 | JSON_VALUE 19 | 20 | inherit 21 | HASHABLE 22 | 23 | DEBUG_OUTPUT 24 | 25 | feature -- Status report 26 | 27 | is_string: BOOLEAN 28 | -- Is Current a string value? 29 | do 30 | end 31 | 32 | is_number: BOOLEAN 33 | -- Is Current a number value? 34 | do 35 | end 36 | 37 | is_object: BOOLEAN 38 | -- Is Current an object value? 39 | do 40 | end 41 | 42 | is_array: BOOLEAN 43 | -- Is Current an array value? 44 | do 45 | end 46 | 47 | is_null: BOOLEAN 48 | -- Is Current a null value? 49 | do 50 | end 51 | 52 | feature -- Access 53 | 54 | has_key (a_key: JSON_STRING): BOOLEAN 55 | -- Has Current an item associated with `a_key`? 56 | -- relevant for object and array values! 57 | do 58 | end 59 | 60 | chained_item alias "@" (a_key: JSON_STRING): JSON_VALUE 61 | -- Item associated with key `a_key` if exists. 62 | -- Note: if item does not exists, return also JSON_NULL. 63 | do 64 | create {JSON_NULL} Result 65 | end 66 | 67 | feature -- Status report 68 | 69 | same_string (a_string: READABLE_STRING_GENERAL): BOOLEAN 70 | -- Current value is a string value, and same content as `a_string`? 71 | do 72 | -- To redefined in descendants. 73 | end 74 | 75 | same_caseless_string (a_string: READABLE_STRING_GENERAL): BOOLEAN 76 | -- Current value is a string value, and same caseless content as `a_string`? 77 | do 78 | -- To redefined in descendants. 79 | end 80 | 81 | feature -- Conversion 82 | 83 | representation: STRING 84 | -- UTF-8 encoded Unicode string representation of Current 85 | deferred 86 | end 87 | 88 | feature -- Visitor pattern 89 | 90 | accept (a_visitor: JSON_VISITOR) 91 | -- Accept `a_visitor'. 92 | -- (Call `visit_*' procedure on `a_visitor'.) 93 | require 94 | a_visitor_not_void: a_visitor /= Void 95 | deferred 96 | end 97 | 98 | note 99 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 100 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 101 | end 102 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/custom/team_json_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEAM_JSON_SERIALIZER}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEAM_JSON_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | local 16 | j_object, j_dico: JSON_OBJECT 17 | j_array: JSON_ARRAY 18 | j_value: detachable JSON_VALUE 19 | i: INTEGER 20 | do 21 | if attached {TEAM} obj as grp then 22 | create j_object.make_with_capacity (2) 23 | -- "name" 24 | j_object.put_string (grp.name, "name") 25 | 26 | -- "owner" 27 | if attached grp.owner as p then 28 | ctx.on_field_start ("owner") 29 | j_value := ctx.to_json (p, Current) 30 | if j_value /= Void then 31 | j_object.put (j_value, "owner") 32 | else 33 | check type_serializable: False end 34 | end 35 | ctx.on_field_end ("owner") 36 | end 37 | 38 | -- "persons" 39 | if attached grp.persons as lst then 40 | ctx.on_field_start ("persons") 41 | create j_array.make (lst.count) 42 | across 43 | lst as ic 44 | loop 45 | j_value := ctx.to_json (ic.item, Current) 46 | if j_value = Void then 47 | check type_serializable: False end 48 | create {JSON_NULL} j_value 49 | end 50 | j_array.extend (j_value) 51 | end 52 | j_object.put (j_array, "persons") 53 | ctx.on_field_end ("persons") 54 | end 55 | 56 | -- "vectors" 57 | create j_array.make (grp.vectors.count) 58 | ctx.on_field_start ("vectors") 59 | i := 1 60 | across 61 | grp.vectors as ic 62 | loop 63 | ctx.on_field_start (i.out) 64 | j_value := ctx.to_json (ic.item, Current) 65 | if j_value = Void then 66 | check type_serializable: False end 67 | create {JSON_NULL} j_value 68 | end 69 | j_array.extend (j_value) 70 | ctx.on_field_end (i.out) 71 | i := i + 1 72 | end 73 | ctx.on_field_end ("vectors") 74 | j_object.put (j_array, "vectors") 75 | 76 | -- "dico" 77 | create j_dico.make_with_capacity (grp.dico.count) 78 | ctx.on_field_start ("dico") 79 | i := 1 80 | across 81 | grp.dico as ic 82 | loop 83 | ctx.on_field_start (ic.key) 84 | j_value := ctx.to_json (ic.item, Current) 85 | if j_value = Void then 86 | check type_serializable: False end 87 | create {JSON_NULL} j_value 88 | end 89 | j_dico.put (j_value, ic.key) 90 | ctx.on_field_end (ic.key) 91 | i := i + 1 92 | end 93 | ctx.on_field_end ("dico") 94 | j_object.put (j_dico, "dico") 95 | 96 | Result := j_object 97 | else 98 | create {JSON_NULL} Result 99 | end 100 | end 101 | 102 | end 103 | -------------------------------------------------------------------------------- /library/serialization/serializer/json_core_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Serialization for basic types." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_CORE_SERIALIZER 8 | 9 | inherit 10 | JSON_SERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 15 | do 16 | if obj = Void then 17 | create {JSON_NULL} Result 18 | else 19 | if attached {BOOLEAN} obj as bool then 20 | create {JSON_BOOLEAN} Result.make (bool) 21 | elseif attached {NUMERIC} obj as num then 22 | if attached {INTEGER_64} num as i64 then 23 | create {JSON_NUMBER} Result.make_integer (i64) 24 | elseif attached {INTEGER_32} num as i32 then 25 | create {JSON_NUMBER} Result.make_integer (i32) 26 | elseif attached {INTEGER_16} num as i16 then 27 | create {JSON_NUMBER} Result.make_integer (i16) 28 | elseif attached {INTEGER_8} num as i8 then 29 | create {JSON_NUMBER} Result.make_integer (i8) 30 | elseif attached {NATURAL_64} num as n64 then 31 | create {JSON_NUMBER} Result.make_natural (n64) 32 | elseif attached {NATURAL_32} num as n32 then 33 | create {JSON_NUMBER} Result.make_natural (n32) 34 | elseif attached {NATURAL_16} num as n16 then 35 | create {JSON_NUMBER} Result.make_natural (n16) 36 | elseif attached {NATURAL_8} num as n8 then 37 | create {JSON_NUMBER} Result.make_natural (n8) 38 | elseif attached {REAL_64} num as r64 then 39 | create {JSON_NUMBER} Result.make_real (r64) 40 | elseif attached {REAL_32} num as r32 then 41 | create {JSON_NUMBER} Result.make_real (r32) 42 | else 43 | check is_basic_numeric_type: False end 44 | create {JSON_NUMBER} Result.make_integer (num.out.to_integer_64) 45 | end 46 | elseif attached {CHARACTER_8} obj as ch8 then 47 | create {JSON_STRING} Result.make_from_string (create {STRING_8}.make_filled (ch8, 1)) 48 | elseif attached {CHARACTER_32} obj as ch32 then 49 | create {JSON_STRING} Result.make_from_string_32 (create {STRING_32}.make_filled (ch32, 1)) 50 | elseif attached {POINTER} obj as ptr then 51 | create {JSON_NUMBER} Result.make_integer (ptr.to_integer_32) 52 | else 53 | Result := reference_to_json (obj, ctx) 54 | end 55 | end 56 | end 57 | 58 | feature {NONE} -- Implementation 59 | 60 | reference_to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 61 | do 62 | if obj = Void then 63 | create {JSON_NULL} Result 64 | elseif attached {READABLE_STRING_GENERAL} obj as str then 65 | -- Never reuse string value ... as reference. 66 | -- CHECK: or maybe for big string ? 67 | create {JSON_STRING} Result.make_from_string_general (str) 68 | else 69 | create {JSON_NULL} Result 70 | end 71 | end 72 | 73 | note 74 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 75 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 76 | end 77 | -------------------------------------------------------------------------------- /examples/serialization/demo_custom_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Enter class description here! 4 | ]" 5 | 6 | class 7 | DEMO_CUSTOM_SERIALIZATION 8 | 9 | inherit 10 | OUTPUT_UTILITIES 11 | 12 | create 13 | make 14 | 15 | feature {NONE} -- Initialization 16 | 17 | make 18 | local 19 | fac: JSON_SERIALIZATION_FACTORY 20 | conv: JSON_SERIALIZATION 21 | p,p2: PERSON 22 | t: TEAM 23 | s: STRING 24 | do 25 | p := person_john_smith 26 | 27 | create conv 28 | -- When converting to JSON, use pretty indented JSON formatting. 29 | conv.set_pretty_printing 30 | 31 | -- for PERSON_DETAILS, we could use a custom serialization, 32 | -- but let's use the "reflector" one. 33 | -- An annoyance is the "$TYPE" attribute in the JSON, 34 | -- if this is an issue, you can disable it via 35 | -- `conv.context.serializer_context.set_is_type_name_included (False)` 36 | -- or build a custom serialization for this type PERSON_DETAILS 37 | conv.register_default (create {JSON_REFLECTOR_SERIALIZATION}) 38 | 39 | -- For PERSON and TEAM, let's use custom serializtion 40 | -- i.e serializer and deserializer know the model interfaces, 41 | -- and know how to generate or use the JSON text. 42 | conv.register (create {PERSON_JSON_SERIALIZATION}, {detachable PERSON}) 43 | 44 | s := conv.to_json_string (p) 45 | print (s) 46 | print ("%N") 47 | 48 | if attached {PERSON} conv.from_json_string (s, {PERSON}) as l_person then 49 | print (l_person) 50 | end 51 | 52 | --| Now let's introduce a new class TEAM 53 | 54 | -- And let's also use a custom serialization 55 | -- i.e serializer and deserializer know the model interfaces, 56 | -- and know how to generate or use the JSON text. 57 | conv.register (create {TEAM_JSON_SERIALIZATION}, {detachable TEAM}) 58 | 59 | -- New team "The testers" 60 | create t.make ("The testers") 61 | p2 := person_gustave_eiffel 62 | t.put (p) 63 | t.put (p2) 64 | p.add_co_worker (p2) 65 | print (t) 66 | 67 | -- Generate the JSON string from this instance of TEAM. 68 | s := conv.to_json_string (t) 69 | print (s) 70 | print ("%N") 71 | 72 | -- Check the roundtrip solution, and build a new TEAM object from the JSON string. 73 | if attached {TEAM} conv.from_json_string (s, {TEAM}) as l_team then 74 | -- It should have the same content. 75 | print (l_team) 76 | if s.same_string (conv.to_json_string (l_team)) then 77 | print ("Deserialization completed successfully.%N") 78 | else 79 | print ("Data lost during deserialization!%N") 80 | end 81 | end 82 | end 83 | 84 | feature -- Object factory 85 | 86 | person_john_smith: PERSON 87 | do 88 | create Result.make ("John", "Smith") 89 | Result.set_details (create {PERSON_DETAILS}.make (10001, "New York", "USA")) 90 | end 91 | 92 | person_gustave_eiffel: PERSON 93 | do 94 | create Result.make ("Gustave", "Eiffel") 95 | Result.set_details (create {PERSON_DETAILS}.make (75007, "Paris", "France")) 96 | end 97 | 98 | end 99 | -------------------------------------------------------------------------------- /library/serialization/printer/json_serialization_visitor.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON_SERIALIZATION_VISITOR Generates a compact JSON-String for a JSON_VALUE" 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_SERIALIZATION_VISITOR 8 | 9 | inherit 10 | JSON_VISITOR 11 | 12 | create 13 | make 14 | 15 | feature -- Initialization 16 | 17 | make (a_output: like output) 18 | -- Create a new instance 19 | do 20 | output := a_output 21 | end 22 | 23 | feature -- Access 24 | 25 | output: STRING_GENERAL 26 | -- JSON representation 27 | 28 | feature -- Visitor Pattern 29 | 30 | visit_json_array (a_json_array: JSON_ARRAY) 31 | -- Visit `a_json_array'. 32 | local 33 | value: JSON_VALUE 34 | l_json_array: ARRAYED_LIST [JSON_VALUE] 35 | l_output: like output 36 | do 37 | l_output := output 38 | l_json_array := a_json_array.array_representation 39 | l_output.append_code (91) -- '[' : 91 40 | from 41 | l_json_array.start 42 | until 43 | l_json_array.off 44 | loop 45 | value := l_json_array.item 46 | value.accept (Current) 47 | l_json_array.forth 48 | if not l_json_array.after then 49 | l_output.append_code (44) -- ',' : 44 50 | end 51 | end 52 | l_output.append_code (93) -- ']' : 93 53 | end 54 | 55 | visit_json_boolean (a_json_boolean: JSON_BOOLEAN) 56 | -- Visit `a_json_boolean'. 57 | do 58 | if a_json_boolean.item then 59 | output.append ("true") 60 | else 61 | output.append ("false") 62 | end 63 | end 64 | 65 | visit_json_null (a_json_null: JSON_NULL) 66 | -- Visit `a_json_null'. 67 | do 68 | output.append ("null") 69 | end 70 | 71 | visit_json_number (a_json_number: JSON_NUMBER) 72 | -- Visit `a_json_number'. 73 | do 74 | output.append (a_json_number.item) 75 | end 76 | 77 | visit_json_object (a_json_object: JSON_OBJECT) 78 | -- Visit `a_json_object'. 79 | local 80 | l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING] 81 | l_output: like output 82 | do 83 | l_output := output 84 | l_pairs := a_json_object.map_representation 85 | l_output.append_code (123) -- '{' : 123 86 | from 87 | l_pairs.start 88 | until 89 | l_pairs.off 90 | loop 91 | l_pairs.key_for_iteration.accept (Current) 92 | l_output.append_code (58) -- ':' : 58 93 | l_pairs.item_for_iteration.accept (Current) 94 | l_pairs.forth 95 | if not l_pairs.after then 96 | l_output.append_code (44) -- ',' : 44 97 | end 98 | end 99 | l_output.append_code (125) -- '}' : 125 100 | end 101 | 102 | visit_json_string (a_json_string: JSON_STRING) 103 | -- Visit `a_json_string'. 104 | local 105 | l_output: like output 106 | do 107 | l_output := output 108 | l_output.append_code (34) -- '%"' : 34 109 | l_output.append (a_json_string.item) 110 | l_output.append_code (34) -- '%"' : 34 111 | end 112 | 113 | note 114 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 115 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 116 | end 117 | 118 | -------------------------------------------------------------------------------- /library/parser/json_reader.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Objects that ..." 3 | author: "jvelilla" 4 | date: "$Date$" 5 | revision: "0.1" 6 | 7 | class 8 | JSON_READER 9 | 10 | create 11 | make 12 | 13 | feature {NONE} -- Initialization 14 | 15 | make (a_json: READABLE_STRING_8) 16 | -- Initialize Reader 17 | do 18 | set_representation (a_json) 19 | end 20 | 21 | feature -- Commands 22 | 23 | reset 24 | -- Reset reader 25 | do 26 | index := 1 27 | end 28 | 29 | set_representation (a_json: READABLE_STRING_8) 30 | -- Set `representation'. 31 | do 32 | representation := a_json.to_string_8 33 | representation.left_adjust 34 | representation.right_adjust 35 | reset 36 | end 37 | 38 | read: CHARACTER 39 | -- Read character 40 | do 41 | if not representation.is_empty then 42 | Result := representation.item (index) 43 | end 44 | end 45 | 46 | next 47 | -- Move to next index 48 | require 49 | has_more_elements: has_next 50 | do 51 | index := index + 1 52 | ensure 53 | incremented: old index + 1 = index 54 | end 55 | 56 | previous 57 | -- Move to previous index 58 | require 59 | not_is_first: has_previous 60 | do 61 | index := index - 1 62 | ensure 63 | incremented: old index - 1 = index 64 | end 65 | 66 | skip_white_spaces 67 | -- Remove white spaces 68 | local 69 | c: like actual 70 | do 71 | from 72 | c := actual 73 | until 74 | (c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T') or not has_next 75 | loop 76 | next 77 | c := actual 78 | end 79 | end 80 | 81 | json_substring (start_index, end_index: INTEGER_32): STRING 82 | -- JSON representation between `start_index' and `end_index' 83 | do 84 | Result := representation.substring (start_index, end_index) 85 | end 86 | 87 | has_json_substring (a_string: READABLE_STRING_GENERAL; start_index, end_index: INTEGER_32): BOOLEAN 88 | -- Has JSON representation between `start_index' and `end_index' the substring `a_string' 89 | do 90 | Result := representation.same_caseless_characters_general (a_string, start_index, end_index, index) 91 | end 92 | 93 | feature -- Status report 94 | 95 | has_next: BOOLEAN 96 | -- Has a next character? 97 | do 98 | Result := index <= representation.count 99 | end 100 | 101 | has_previous: BOOLEAN 102 | -- Has a previous character? 103 | do 104 | Result := index >= 1 105 | end 106 | 107 | feature -- Access 108 | 109 | representation: STRING 110 | -- Serialized representation of the original JSON string 111 | 112 | feature {NONE} -- Implementation 113 | 114 | actual: CHARACTER 115 | -- Current character or '%U' if none 116 | do 117 | if index > representation.count then 118 | Result := '%U' 119 | else 120 | Result := representation.item (index) 121 | end 122 | end 123 | 124 | index: INTEGER 125 | -- Actual index 126 | 127 | invariant 128 | representation_not_void: representation /= Void 129 | 130 | note 131 | copyright: "2010-2019, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 132 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 133 | end 134 | -------------------------------------------------------------------------------- /library/serialization/json_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Utility interface to use JSON (de)serialization." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_SERIALIZATION 8 | 9 | inherit 10 | ANY 11 | redefine 12 | default_create 13 | end 14 | 15 | create 16 | default_create, 17 | make_with_context 18 | 19 | feature {NONE} -- Initialization 20 | 21 | default_create 22 | do 23 | make_with_context (create {JSON_SERIALIZATION_CONTEXT}) 24 | end 25 | 26 | make_with_context (ctx: JSON_SERIALIZATION_CONTEXT) 27 | do 28 | context := ctx 29 | end 30 | 31 | feature -- Access 32 | 33 | context: JSON_SERIALIZATION_CONTEXT 34 | -- Context related to serialization and deserialization. 35 | 36 | feature -- Status 37 | 38 | has_deserialization_error: BOOLEAN 39 | -- Error occurred during deserialization? 40 | do 41 | Result := context.has_deserialization_error 42 | end 43 | 44 | feature -- Element change 45 | 46 | set_pretty_printing 47 | -- Generate pretty indented JSON for `to_json_string'. 48 | do 49 | context.set_pretty_printing 50 | end 51 | 52 | set_compact_printing 53 | -- Generate compact JSON for `to_json_string'. 54 | do 55 | context.set_compact_printing 56 | end 57 | 58 | register (a_serialization: JSON_SERIALIZATION_I; a_type: TYPE [detachable ANY]) 59 | do 60 | if attached {JSON_SERIALIZER} a_serialization as s then 61 | context.register_serializer (s, a_type) 62 | end 63 | if attached {JSON_DESERIALIZER} a_serialization as d then 64 | context.register_deserializer (d, a_type) 65 | end 66 | end 67 | 68 | register_default (a_serialization: JSON_SERIALIZATION_I) 69 | do 70 | if attached {JSON_SERIALIZER} a_serialization as s then 71 | context.set_default_serializer (s) 72 | end 73 | if attached {JSON_DESERIALIZER} a_serialization as d then 74 | context.set_default_deserializer (d) 75 | end 76 | end 77 | 78 | 79 | feature -- Cleaning 80 | 81 | reset 82 | -- Clean temporary data if relevant. 83 | do 84 | context.reset 85 | end 86 | 87 | feature -- Conversion to JSON 88 | 89 | to_json (obj: detachable ANY): JSON_VALUE 90 | do 91 | if obj = Void then 92 | create {JSON_NULL} Result 93 | elseif attached context.to_json (obj, Void) as j then 94 | Result := j 95 | else 96 | create {JSON_NULL} Result -- FIXME 97 | end 98 | end 99 | 100 | append_to_json_string (obj: detachable ANY; a_output: STRING_GENERAL) 101 | do 102 | append_json_to_string (to_json (obj), a_output) 103 | end 104 | 105 | to_json_string (obj: detachable ANY): STRING 106 | do 107 | create Result.make (0) 108 | append_to_json_string (obj, Result) 109 | end 110 | 111 | feature -- Conversion from JSON 112 | 113 | from_json (a_json: detachable JSON_VALUE; a_type: TYPE [detachable ANY]): detachable ANY 114 | do 115 | Result := context.value_from_json (a_json, a_type) 116 | if context.has_deserialization_error then 117 | Result := Void 118 | end 119 | end 120 | 121 | from_json_string (a_json_string: STRING; a_type: TYPE [detachable ANY]): detachable ANY 122 | do 123 | Result := from_json (json_from_string (a_json_string), a_type) 124 | end 125 | 126 | feature -- Helper 127 | 128 | append_json_to_string (a_json: JSON_VALUE; a_output: STRING_GENERAL) 129 | local 130 | vis: JSON_VISITOR 131 | do 132 | if context.is_pretty_printing then 133 | create {JSON_PRETTY_STRING_VISITOR} vis.make (a_output) 134 | else 135 | create {JSON_SERIALIZATION_VISITOR} vis.make (a_output) 136 | end 137 | a_json.accept (vis) 138 | end 139 | 140 | json_from_string (a_json_string: STRING): detachable JSON_VALUE 141 | local 142 | p: JSON_PARSER 143 | do 144 | create p.make_with_string (a_json_string) 145 | p.parse_content 146 | if 147 | p.is_parsed and then p.is_valid 148 | then 149 | Result := p.parsed_json_value 150 | end 151 | end 152 | 153 | note 154 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 155 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 156 | end 157 | -------------------------------------------------------------------------------- /library/serialization/with_reference/json_deserializer_context_with_reference.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Context for the deserialization." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_DESERIALIZER_CONTEXT_WITH_REFERENCE 8 | 9 | inherit 10 | JSON_DESERIALIZER_CONTEXT 11 | redefine 12 | default_create, 13 | value_from_json, 14 | on_object, 15 | reset 16 | end 17 | 18 | create 19 | default_create 20 | 21 | feature {NONE} -- Initialization 22 | 23 | default_create 24 | do 25 | Precursor 26 | create deserialized_references.make (1) 27 | reference_target_field_name := "$REF" 28 | reference_source_field_name := "$REF#" 29 | end 30 | 31 | feature -- Cleaning 32 | 33 | reset 34 | -- Clean any temporary data, to release memory or reset computation. 35 | do 36 | deserialized_references.wipe_out 37 | Precursor 38 | end 39 | 40 | feature -- Factory 41 | 42 | value_from_json (a_json: detachable JSON_VALUE; a_type: detachable TYPE [detachable ANY]): detachable ANY 43 | do 44 | if 45 | attached {JSON_OBJECT} a_json as j_object and then 46 | j_object.count = 1 and then 47 | attached {JSON_STRING} j_object.item (reference_target_field_name) as j_ref 48 | then 49 | -- Is a reference, since a JSON_OBJECT with a unique field named "$REF"! 50 | Result := recorded_deserialized_reference (j_ref.unescaped_string_32) 51 | else 52 | -- Not a reference, i.e does not have "$REF" as field name ! 53 | Result := Precursor (a_json, a_type) 54 | end 55 | end 56 | 57 | feature -- Field names 58 | 59 | reference_target_field_name: READABLE_STRING_8 assign set_reference_target_field_name 60 | -- Field name related to reference. 61 | -- Default: $REF 62 | 63 | reference_source_field_name: READABLE_STRING_8 assign set_reference_source_field_name 64 | -- Field name related to reference identifier. 65 | -- Default: $REF# 66 | 67 | feature -- Field name changes 68 | 69 | set_reference_target_field_name (a_name: READABLE_STRING_8) 70 | do 71 | reference_target_field_name := a_name 72 | end 73 | 74 | set_reference_source_field_name (a_name: READABLE_STRING_8) 75 | do 76 | reference_source_field_name := a_name 77 | end 78 | 79 | feature -- Callback event 80 | 81 | on_object (obj: ANY; a_json_object: JSON_OBJECT) 82 | -- Event triggered when object `obj' is just instantiated or fully deserialized from `a_json_object'. 83 | do 84 | Precursor (obj, a_json_object) 85 | 86 | -- If it has a "$REF#" field, another value is referencing this `obj' 87 | -- thus record it for later access by the other value. 88 | if attached {JSON_STRING} a_json_object.item (reference_source_field_name) as j_str then 89 | record_deserialized_reference (obj, j_str.unescaped_string_32) 90 | end 91 | end 92 | 93 | on_object_referenced (obj: ANY; a_ref_id: READABLE_STRING_GENERAL) 94 | -- Event trigger when an object `obj' is associated with an identifier `a_ref_id'. 95 | do 96 | record_deserialized_reference (obj, a_ref_id) 97 | end 98 | 99 | feature -- References record 100 | 101 | deserialized_references: STRING_TABLE [detachable ANY] 102 | 103 | record_deserialized_reference (obj: ANY; a_ref_id: READABLE_STRING_GENERAL) 104 | do 105 | deserialized_references.force (obj, a_ref_id) 106 | end 107 | 108 | discard_deserialized_reference (a_ref_id: READABLE_STRING_GENERAL) 109 | do 110 | deserialized_references.remove (a_ref_id) 111 | end 112 | 113 | reference_identifier_from (a_json_object: JSON_OBJECT): detachable READABLE_STRING_GENERAL 114 | do 115 | if attached {JSON_STRING} a_json_object.item (reference_target_field_name) as s_ref then 116 | Result := s_ref.unescaped_string_32 117 | end 118 | end 119 | 120 | recorded_deserialized_reference (a_ref: READABLE_STRING_GENERAL): detachable ANY 121 | do 122 | if Result = Void then 123 | Result := deserialized_references.item (a_ref) 124 | end 125 | end 126 | 127 | ;note 128 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 129 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 130 | end 131 | -------------------------------------------------------------------------------- /library/serialization/json_serialization_context.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON Serialization context for JSON serializer and JSON deserializer. 4 | 5 | By default, it is using the reflection mechanism. 6 | But this should be applied only on recursively "expanded" object (i.e without any cycle). 7 | ]" 8 | date: "$Date$" 9 | revision: "$Revision$" 10 | 11 | class 12 | JSON_SERIALIZATION_CONTEXT 13 | 14 | inherit 15 | ANY 16 | redefine 17 | default_create 18 | end 19 | 20 | create 21 | default_create, 22 | make_with_context 23 | 24 | feature {NONE} -- Initialization 25 | 26 | default_create 27 | do 28 | make_with_context (create {like serializer_context}, create {like deserializer_context}) 29 | end 30 | 31 | make_with_context (a_serializer_context: like serializer_context; a_deserializer_context: like deserializer_context) 32 | do 33 | serializer_context := a_serializer_context 34 | deserializer_context := a_deserializer_context 35 | end 36 | 37 | feature -- Settings 38 | 39 | is_pretty_printing: BOOLEAN 40 | do 41 | Result := serializer_context.is_pretty_printing 42 | end 43 | 44 | feature -- Settings change 45 | 46 | set_pretty_printing 47 | do 48 | serializer_context.set_pretty_printing 49 | end 50 | 51 | set_compact_printing 52 | do 53 | serializer_context.set_compact_printing 54 | end 55 | 56 | feature -- Access 57 | 58 | serializer_context: JSON_SERIALIZER_CONTEXT 59 | -- Context for serialization. 60 | 61 | deserializer_context: JSON_DESERIALIZER_CONTEXT 62 | -- Context for deserialization. 63 | 64 | feature -- Serialization 65 | 66 | to_json (obj: ANY; a_caller_serializer: detachable JSON_SERIALIZER): detachable JSON_VALUE 67 | do 68 | Result := serializer_context.to_json (obj, a_caller_serializer) 69 | end 70 | 71 | feature -- Deserialization 72 | 73 | value_from_json (a_json: detachable JSON_VALUE; a_type: detachable TYPE [detachable ANY]): detachable ANY 74 | do 75 | Result := deserializer_context.value_from_json (a_json, a_type) 76 | end 77 | 78 | has_deserialization_error: BOOLEAN 79 | -- Error occurred during deserialization? 80 | do 81 | Result := deserializer_context.has_error 82 | end 83 | 84 | deserialization_error: detachable JSON_DESERIALIZER_ERROR 85 | -- Error related to deserialization, if any. 86 | do 87 | Result := deserializer_context.error 88 | ensure 89 | Result /= Void implies has_deserialization_error 90 | end 91 | 92 | feature -- Element change 93 | 94 | register_serializer (conv: JSON_SERIALIZER; a_type: TYPE [detachable ANY]) 95 | do 96 | serializer_context.register_serializer (conv, a_type) 97 | end 98 | 99 | set_default_serializer (conv: detachable JSON_SERIALIZER) 100 | do 101 | serializer_context.set_default_serializer (conv) 102 | end 103 | 104 | register_deserializer (conv: JSON_DESERIALIZER; a_type: TYPE [detachable ANY]) 105 | do 106 | deserializer_context.register_deserializer (conv, a_type) 107 | end 108 | 109 | set_default_deserializer (conv: detachable JSON_DESERIALIZER) 110 | do 111 | deserializer_context.set_default_deserializer (conv) 112 | end 113 | 114 | feature -- Cleaning 115 | 116 | reset 117 | -- Clean temporary data if relevant. 118 | do 119 | serializer_context.reset 120 | deserializer_context.reset 121 | end 122 | 123 | feature -- Element change 124 | 125 | register (a_serialization: JSON_SERIALIZATION_I; a_type: TYPE [detachable ANY]) 126 | do 127 | if attached {JSON_SERIALIZER} a_serialization as s then 128 | serializer_context.register_serializer (s, a_type) 129 | end 130 | if attached {JSON_DESERIALIZER} a_serialization as d then 131 | deserializer_context.register_deserializer (d, a_type) 132 | end 133 | end 134 | 135 | set_default (a_serialization: detachable JSON_SERIALIZATION_I) 136 | do 137 | if a_serialization = Void then 138 | serializer_context.set_default_serializer (Void) 139 | deserializer_context.set_default_deserializer (Void) 140 | else 141 | if attached {JSON_SERIALIZER} a_serialization as s then 142 | serializer_context.set_default_serializer (s) 143 | end 144 | if attached {JSON_DESERIALIZER} a_serialization as d then 145 | deserializer_context.set_default_deserializer (d) 146 | end 147 | end 148 | end 149 | 150 | note 151 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 152 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 153 | end 154 | -------------------------------------------------------------------------------- /library/serialization/with_reference/json_serializer_context_with_reference.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Context for JSON serialization." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_SERIALIZER_CONTEXT_WITH_REFERENCE 8 | 9 | inherit 10 | JSON_SERIALIZER_CONTEXT 11 | redefine 12 | default_create, 13 | reset, 14 | is_accepted_object, 15 | on_object_serialization_start, 16 | on_object_serialization_end, 17 | to_json 18 | end 19 | 20 | create 21 | default_create 22 | 23 | feature {NONE} -- Initialization 24 | 25 | default_create 26 | do 27 | Precursor 28 | reference_target_field_name := "$REF" 29 | create serialized_references.make ("$REF#") 30 | debug ("json_serialization") 31 | serialized_references.use_verbose_reference_identifier 32 | end 33 | end 34 | 35 | feature -- Settings 36 | 37 | using_verbose_reference_identifier: BOOLEAN 38 | -- Using verbose longer identifier for the reference values. 39 | -- Default: False 40 | do 41 | Result := serialized_references.using_verbose_reference_identifier 42 | end 43 | 44 | reference_target_field_name: READABLE_STRING_8 assign set_reference_target_field_name 45 | -- Field name related to reference. 46 | -- Default: $REF 47 | 48 | reference_source_field_name: READABLE_STRING_8 assign set_reference_source_field_name 49 | -- Field name related to reference identifier. 50 | -- Default: $REF# 51 | do 52 | Result := serialized_references.reference_source_field_name 53 | end 54 | 55 | feature -- Settings change 56 | 57 | use_verbose_reference_identifier 58 | -- Use long verbose identifier for reference. 59 | -- Useful for debugging. 60 | do 61 | serialized_references.use_verbose_reference_identifier 62 | end 63 | 64 | use_shortest_reference_identifier 65 | -- Use shortest identifier for reference (based on an integer counter). 66 | do 67 | serialized_references.use_shortest_reference_identifier 68 | end 69 | 70 | set_reference_target_field_name (a_name: READABLE_STRING_8) 71 | do 72 | reference_target_field_name := a_name 73 | end 74 | 75 | set_reference_source_field_name (a_name: READABLE_STRING_8) 76 | do 77 | serialized_references.reference_source_field_name := a_name 78 | end 79 | 80 | feature -- Status 81 | 82 | is_accepted_object (obj: detachable ANY): BOOLEAN 83 | -- Is `obj' accepted for serialization? 84 | -- ie: when cycle are forbidden, it should be recursively expanded. 85 | do 86 | Result := True 87 | end 88 | 89 | feature -- Cleaning 90 | 91 | reset 92 | -- Clean any temporary data, to release memory or reset computation. 93 | do 94 | Precursor 95 | serialized_references.reset 96 | end 97 | 98 | feature -- Callback events 99 | 100 | on_object_serialization_start (a_obj: ANY) 101 | -- Event triggered just before processing object `a_obj'. 102 | do 103 | Precursor (a_obj) 104 | if attached {READABLE_STRING_GENERAL} a_obj then 105 | -- Do not record string value! 106 | else 107 | record_reference (Void, a_obj) 108 | end 109 | end 110 | 111 | on_object_serialization_end (j_value: JSON_VALUE; a_obj: ANY) 112 | -- Event triggered just after having object `a_obj' processed with associated `j_value' json value.. 113 | --| `j_value' is either JSON_STRING, JSON_OBJECT or JSON_ARRAY. 114 | do 115 | Precursor (j_value, a_obj) 116 | record_reference (j_value, a_obj) 117 | end 118 | 119 | feature -- References 120 | 121 | record_reference (j_value: detachable JSON_VALUE; a_obj: ANY) 122 | -- Record json value `j_value' for object `a_obj' 123 | -- and associate with a reference identifier computed internally. 124 | do 125 | serialized_references.record (a_obj, j_value, Current) 126 | end 127 | 128 | recorded_json_value (obj: ANY): detachable JSON_OBJECT 129 | -- JSON value representing the reference `obj' if already recorded. 130 | do 131 | if attached serialized_references.item (obj) as s_ref then 132 | create Result.make_with_capacity (1) 133 | Result.put_string (s_ref, reference_target_field_name) 134 | end 135 | end 136 | 137 | feature -- Helpers 138 | 139 | to_json (obj: ANY; a_caller_serializer: detachable JSON_SERIALIZER): detachable JSON_VALUE 140 | do 141 | if attached recorded_json_value (obj) as j then 142 | Result := j 143 | else 144 | Result := Precursor (obj, a_caller_serializer) 145 | end 146 | end 147 | 148 | feature {NONE} -- Implementation: cycle 149 | 150 | serialized_references: JSON_SERIALIZER_REFERENCE_COLLECTION 151 | 152 | ;note 153 | copyright: "2016-2016, Jocelyn Fiat and Eiffel Software" 154 | license: "Eiffel Forum License v2 (see https://www.eiffel.com/licensing/forum.txt)" 155 | end 156 | -------------------------------------------------------------------------------- /examples/serialization/application_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | Collection of JSON serialization examples. 4 | ]" 5 | 6 | class 7 | APPLICATION_SERIALIZATION 8 | 9 | create 10 | make 11 | 12 | feature {NONE} -- Initialization 13 | 14 | make 15 | do 16 | demonstrate_custom_serialization 17 | demonstrate_basic_serialization 18 | demonstrate_reflector_serialization 19 | demonstrate_smart_serialization 20 | end 21 | 22 | feature -- Example 23 | 24 | demonstrate_custom_serialization 25 | local 26 | l_custom: DEMO_CUSTOM_SERIALIZATION 27 | do 28 | -- Example of custom serialization 29 | create l_custom.make 30 | end 31 | 32 | demonstrate_basic_serialization 33 | local 34 | l_basic: DEMO_BASIC_SERIALIZATION 35 | do 36 | -- Example of basic serialization 37 | create l_basic.make 38 | end 39 | 40 | demonstrate_reflector_serialization 41 | -- Use reflector serialization, mostly for storage since the serialized json contains internal attributes... 42 | -- So not a simple json output. 43 | local 44 | fac: JSON_SERIALIZATION_FACTORY 45 | conv: JSON_SERIALIZATION 46 | obj: like new_object 47 | do 48 | print ("%N") 49 | print ("=====================================================%N") 50 | print ("= Serialization using only Reflection functionality =%N") 51 | print ("=====================================================%N") 52 | print ("%N") 53 | obj := new_object 54 | 55 | conv := fac.reflector_serialization 56 | 57 | conv.set_pretty_printing 58 | if attached conv.to_json_string (obj) as s then 59 | print ("Object to json:%N") 60 | print (s) 61 | print ("%N") 62 | 63 | if attached {like new_object} conv.from_json_string (s, {STRING_TABLE [ARRAYED_LIST [ANY]]}) as l_obj then 64 | print ("JSON to object:%N") 65 | print (conv.to_json_string (l_obj)) 66 | print ("%N") 67 | print (l_obj.item ("abc")) 68 | print (l_obj.item ("123")) 69 | elseif conv.has_deserialization_error then 70 | print ("Error occurred!%N") 71 | if attached conv.context.deserialization_error as err then 72 | print (err.all_messages_as_string) 73 | end 74 | end 75 | end 76 | end 77 | 78 | demonstrate_smart_serialization 79 | -- Use smart serialization, i.e use json array [ .. ] and json object { .. : .. }. 80 | -- And deserialization is made possible thanks to specific callback. 81 | local 82 | fac: JSON_SERIALIZATION_FACTORY 83 | conv: JSON_SERIALIZATION 84 | obj: like new_object 85 | do 86 | print ("%N") 87 | print ("============================================================================%N") 88 | print ("= Serialization to simple json formating, and deserialization via callback =%N") 89 | print ("============================================================================%N") 90 | print ("%N") 91 | obj := new_object 92 | 93 | conv := fac.smart_serialization 94 | 95 | conv.set_pretty_printing 96 | if attached conv.to_json_string (obj) as s then 97 | print ("Object to json:%N") 98 | print (s) 99 | print ("%N") 100 | 101 | -- For deserialization, we need to help with a callback to create expected objects for specific json types 102 | -- such as JSON Array and some JSON object (as dictionary). 103 | conv.context.deserializer_context.set_value_creation_callback (create {JSON_DESERIALIZER_CREATION_AGENT_CALLBACK}.make ( 104 | agent (a_info: JSON_DESERIALIZER_CREATION_INFORMATION) 105 | do 106 | if a_info.static_type = {ARRAYED_LIST [ANY]} then 107 | a_info.set_object (create {ARRAYED_LIST [ANY]}.make (0)) 108 | elseif a_info.static_type = {STRING_TABLE [ARRAYED_LIST [ANY]]} then 109 | a_info.set_object (create {STRING_TABLE [ARRAYED_LIST [ANY]]}.make (0)) 110 | end 111 | end 112 | ) 113 | ) 114 | if attached conv.from_json_string (s, {STRING_TABLE [ARRAYED_LIST [ANY]]}) as l_obj then 115 | print ("JSON to object:%N") 116 | print (conv.to_json_string (l_obj)) 117 | print ("%N") 118 | elseif conv.has_deserialization_error then 119 | print ("Error occurred!%N") 120 | if attached conv.context.deserialization_error as err then 121 | print (err.all_messages_as_string) 122 | end 123 | end 124 | end 125 | end 126 | 127 | feature -- Object factory 128 | 129 | new_object: STRING_TABLE [ARRAYED_LIST [ANY]] 130 | local 131 | lst: ARRAYED_LIST [ANY] 132 | do 133 | create Result.make (2) 134 | create lst.make (3) 135 | lst.extend ("a") 136 | lst.extend ("b") 137 | lst.extend ("c") 138 | Result.put (lst, "abc") 139 | create lst.make (3) 140 | lst.extend (1) 141 | lst.extend (2) 142 | lst.extend (3) 143 | Result.put (lst, "123") 144 | end 145 | 146 | end 147 | -------------------------------------------------------------------------------- /library/serialization/with_reference/json_serializer_reference_collection.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {JSON_SERIALIZER_REFERENCE_COLLECTION}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_SERIALIZER_REFERENCE_COLLECTION 8 | 9 | create 10 | make 11 | 12 | feature {NONE} -- Initialization 13 | 14 | make (a_ref_id_field_name: READABLE_STRING_8) 15 | do 16 | create json_values.make_caseless (1) 17 | create references.make (1) 18 | reference_source_field_name := a_ref_id_field_name 19 | end 20 | 21 | feature -- Settings 22 | 23 | using_verbose_reference_identifier: BOOLEAN 24 | 25 | reference_source_field_name: READABLE_STRING_8 assign set_reference_source_field_name 26 | -- Field name for reference source. 27 | -- Default: $REF# 28 | 29 | feature -- Settings change 30 | 31 | use_verbose_reference_identifier 32 | -- Use long verbose identifier for reference. 33 | -- Useful for debugging. 34 | do 35 | using_verbose_reference_identifier := True 36 | end 37 | 38 | use_shortest_reference_identifier 39 | -- Use shortest identifier for reference (based on an integer counter). 40 | do 41 | using_verbose_reference_identifier := False 42 | end 43 | 44 | set_reference_source_field_name (a_name: READABLE_STRING_8) 45 | do 46 | reference_source_field_name := a_name 47 | end 48 | 49 | feature -- Cleaning 50 | 51 | reset 52 | do 53 | json_values.wipe_out 54 | references.wipe_out 55 | counter := 0 56 | end 57 | 58 | feature -- Access 59 | 60 | item (obj: ANY): detachable STRING_32 61 | -- Reference on `obj' if any. 62 | -- If reference exists, increase the number of callers. 63 | do 64 | if attached reference_info (obj) as l_info then 65 | l_info.caller_count := l_info.caller_count + 1 66 | Result := l_info.identifier 67 | if attached json_values.item (Result) as jv then 68 | -- In case, the json value is already associated, update it with ref right away. 69 | -- otherwise, it will be done, when the associated is done (when the ref item is fully serialized). 70 | update_reference (jv, Result) 71 | end 72 | end 73 | end 74 | 75 | feature {NONE} -- Implementation 76 | 77 | reference_info (obj: ANY): detachable TUPLE [identifier: STRING_32; value: ANY; caller_count: INTEGER] 78 | do 79 | across 80 | references as ic 81 | until 82 | Result /= Void 83 | loop 84 | if ic.item.value = obj then 85 | Result := ic.item 86 | end 87 | end 88 | end 89 | 90 | update_reference (a_json_value: detachable JSON_VALUE; a_ref: READABLE_STRING_GENERAL) 91 | do 92 | if attached {JSON_OBJECT} a_json_value as j then 93 | if attached {JSON_STRING} j.item (reference_source_field_name) as j_ref_id then 94 | check same_ref: a_ref.same_string (j_ref_id.unescaped_string_32) end 95 | else 96 | j.put_string (a_ref, reference_source_field_name) 97 | end 98 | else 99 | -- Ignore for String 100 | check False end 101 | end 102 | end 103 | 104 | feature -- Element change 105 | 106 | record (obj: ANY; a_json_value: detachable JSON_VALUE; ctx: JSON_SERIALIZER_CONTEXT) 107 | local 108 | i: INTEGER 109 | s: STRING_32 110 | l_ref: READABLE_STRING_GENERAL 111 | do 112 | if attached reference_info (obj) as l_info then 113 | -- Update associated json value 114 | if l_info.value = a_json_value then 115 | -- Void or 116 | else 117 | l_ref := l_info.identifier 118 | check json_values.item (l_ref) = Void end 119 | if l_info.caller_count > 0 then 120 | update_reference (a_json_value, l_ref) 121 | end 122 | json_values.force (a_json_value, l_ref) 123 | end 124 | else 125 | i := counter + 1 126 | counter := i 127 | if using_verbose_reference_identifier then 128 | create s.make_empty 129 | s.append_integer (i) 130 | s.append_character (':') 131 | s.append_character ('{') 132 | s.append_string_general (obj.generating_type.name) 133 | s.append_character ('}') 134 | s.append_character (':') 135 | s.append_string_general (ctx.serializer_location) 136 | else 137 | s := i.out 138 | end 139 | json_values.force (a_json_value, s) 140 | references.force ([s, obj, 0]) 141 | end 142 | end 143 | 144 | feature {NONE} -- Implementation 145 | 146 | counter: INTEGER 147 | 148 | json_values: STRING_TABLE [detachable JSON_VALUE] 149 | -- indexed by reference identifier. 150 | 151 | references: ARRAYED_LIST [TUPLE [identifier: STRING_32; value: ANY; caller_count: INTEGER]] 152 | -- indexed by reference identifier. 153 | 154 | invariant 155 | json_values.count = references.count 156 | 157 | note 158 | copyright: "2010-2016, Javier Velilla and others https://github.com/eiffelhub/json." 159 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 160 | end 161 | -------------------------------------------------------------------------------- /library/kernel/json_array.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON_ARRAY represent an array in JSON. 4 | An array in JSON is an ordered set of names. 5 | Examples 6 | array 7 | [] 8 | [elements] 9 | ]" 10 | author: "$Author$" 11 | date: "$date$" 12 | revision: "$Revision$" 13 | 14 | class 15 | JSON_ARRAY 16 | 17 | inherit 18 | JSON_VALUE 19 | redefine 20 | is_array, 21 | chained_item 22 | end 23 | 24 | ITERABLE [JSON_VALUE] 25 | 26 | DEBUG_OUTPUT 27 | 28 | create 29 | make, make_empty, 30 | make_array 31 | 32 | feature {NONE} -- Initialization 33 | 34 | make (nb: INTEGER) 35 | -- Initialize JSON array with capacity of `nb' items. 36 | do 37 | create items.make (nb) 38 | end 39 | 40 | make_empty 41 | -- Initialize empty JSON array. 42 | do 43 | make (0) 44 | end 45 | 46 | make_array 47 | -- Initialize JSON Array 48 | obsolete 49 | "Use `make' [2017-05-31]" 50 | do 51 | make (10) 52 | end 53 | 54 | feature -- Status report 55 | 56 | is_array: BOOLEAN = True 57 | -- 58 | 59 | feature -- Access 60 | 61 | i_th alias "[]" (i: INTEGER): JSON_VALUE 62 | -- Item at `i'-th position 63 | require 64 | is_valid_index: valid_index (i) 65 | do 66 | Result := items.i_th (i) 67 | end 68 | 69 | chained_item alias "@" (a_key: JSON_STRING): JSON_VALUE 70 | -- . 71 | do 72 | if a_key.item.is_integer then 73 | Result := i_th (a_key.item.to_integer) 74 | else 75 | Result := Precursor (a_key) 76 | end 77 | end 78 | 79 | representation: STRING 80 | do 81 | Result := "[" 82 | across 83 | items as ic 84 | loop 85 | if Result.count > 1 then 86 | Result.append_character (',') 87 | end 88 | Result.append (ic.item.representation) 89 | end 90 | Result.append_character (']') 91 | end 92 | 93 | feature -- Visitor pattern 94 | 95 | accept (a_visitor: JSON_VISITOR) 96 | -- Accept `a_visitor'. 97 | -- (Call `visit_json_array' procedure on `a_visitor'.) 98 | do 99 | a_visitor.visit_json_array (Current) 100 | end 101 | 102 | feature -- Access 103 | 104 | new_cursor: ITERATION_CURSOR [JSON_VALUE] 105 | -- Fresh cursor associated with current structure 106 | do 107 | Result := items.new_cursor 108 | end 109 | 110 | feature -- Mesurement 111 | 112 | count: INTEGER 113 | -- Number of items. 114 | do 115 | Result := items.count 116 | end 117 | 118 | feature -- Status report 119 | 120 | is_empty: BOOLEAN 121 | -- Is structure empty? 122 | do 123 | Result := count = 0 124 | end 125 | 126 | valid_index (i: INTEGER): BOOLEAN 127 | -- Is `i' a valid index? 128 | do 129 | Result := (1 <= i) and (i <= count) 130 | end 131 | 132 | feature -- Change Element 133 | 134 | put_front (v: JSON_VALUE) 135 | require 136 | v_not_void: v /= Void 137 | do 138 | items.put_front (v) 139 | ensure 140 | has_new_value: old items.count + 1 = items.count and items.first = v 141 | end 142 | 143 | add, extend (v: JSON_VALUE) 144 | require 145 | v_not_void: v /= Void 146 | do 147 | items.extend (v) 148 | ensure 149 | has_new_value: old items.count + 1 = items.count and items.has (v) 150 | end 151 | 152 | prune_all (v: JSON_VALUE) 153 | -- Remove all occurrences of `v'. 154 | require 155 | v_not_void: v /= Void 156 | do 157 | items.prune_all (v) 158 | ensure 159 | not_has_new_value: not items.has (v) 160 | end 161 | 162 | wipe_out 163 | -- Remove all items. 164 | do 165 | items.wipe_out 166 | end 167 | 168 | feature -- Report 169 | 170 | hash_code: INTEGER 171 | -- Hash code value 172 | local 173 | l_started: BOOLEAN 174 | do 175 | across 176 | items as ic 177 | loop 178 | if l_started then 179 | Result := ((Result \\ 8388593) |<< 8) + ic.item.hash_code 180 | else 181 | Result := ic.item.hash_code 182 | l_started := True 183 | end 184 | end 185 | Result := Result \\ items.count 186 | end 187 | 188 | feature -- Conversion 189 | 190 | array_representation: ARRAYED_LIST [JSON_VALUE] 191 | -- Representation as a sequences of values. 192 | -- be careful, modifying the return object may have impact on the original JSON_ARRAY object. 193 | do 194 | Result := items 195 | end 196 | 197 | feature -- Status report 198 | 199 | debug_output: STRING 200 | -- String that should be displayed in debugger to represent `Current'. 201 | do 202 | Result := count.out + " item(s)" 203 | end 204 | 205 | feature {NONE} -- Implementation 206 | 207 | items: ARRAYED_LIST [JSON_VALUE] 208 | -- Value container 209 | 210 | invariant 211 | items_not_void: items /= Void 212 | 213 | note 214 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 215 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 216 | end 217 | -------------------------------------------------------------------------------- /test/autotest/test_suite/serialization/test_json_serializer_with_reference.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "Summary description for {TEST_JSON_SERIALIZER_WITH_REFERENCE}." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | TEST_JSON_SERIALIZER_WITH_REFERENCE 8 | 9 | inherit 10 | TEST_JSON_SERIALIZER 11 | 12 | feature -- Tests 13 | 14 | test_cycle_reflector 15 | local 16 | obj: TEAM 17 | conv_to: JSON_REFLECTOR_SERIALIZER 18 | conv_from: JSON_REFLECTOR_DESERIALIZER 19 | ctx: detachable JSON_SERIALIZER_CONTEXT 20 | ctx_deser: detachable JSON_DESERIALIZER_CONTEXT 21 | s: STRING 22 | do 23 | obj := new_cycling_full_team 24 | 25 | create conv_to 26 | create {JSON_SERIALIZER_CONTEXT_WITH_REFERENCE} ctx 27 | ctx.set_pretty_printing 28 | ctx.is_type_name_included := False -- Do not include the type name info. 29 | 30 | s := conv_to.to_json_string (obj, ctx) 31 | 32 | create conv_from 33 | create {JSON_DESERIALIZER_CONTEXT_WITH_REFERENCE} ctx_deser 34 | ctx_deser.set_default_deserializer (create {JSON_REFLECTOR_DESERIALIZER}) 35 | 36 | if attached conv_from.from_json_string (s, ctx_deser, {TEAM}) as o then 37 | assert ("deserialized error", False) 38 | else 39 | assert ("deserialized reported error and returned Void", ctx_deser.has_error) 40 | end 41 | end 42 | 43 | test_cycle_reflector_with_type_name 44 | local 45 | obj: TEAM 46 | conv_to: JSON_REFLECTOR_SERIALIZER 47 | conv_from: JSON_REFLECTOR_DESERIALIZER 48 | ctx: detachable JSON_SERIALIZER_CONTEXT 49 | ctx_deser: detachable JSON_DESERIALIZER_CONTEXT 50 | s: STRING 51 | do 52 | obj := new_cycling_full_team 53 | 54 | create conv_to 55 | create {JSON_SERIALIZER_CONTEXT_WITH_REFERENCE} ctx 56 | ctx.set_pretty_printing 57 | s := conv_to.to_json_string (obj, ctx) 58 | 59 | create conv_from 60 | create {JSON_DESERIALIZER_CONTEXT_WITH_REFERENCE} ctx_deser 61 | ctx_deser.set_default_deserializer (create {JSON_REFLECTOR_DESERIALIZER}) 62 | 63 | if attached conv_from.from_json_string (s, ctx_deser, {TEAM}) as o then 64 | assert ("deserialized ok", recursively_one_includes_other (obj, o, Void)) 65 | else 66 | assert ("deserialized ok", False) 67 | end 68 | end 69 | 70 | test_cycle_reflector_custom 71 | local 72 | obj: TEAM 73 | conv_to: JSON_REFLECTOR_SERIALIZER 74 | conv_from: JSON_REFLECTOR_DESERIALIZER 75 | ctx: detachable JSON_SERIALIZER_CONTEXT_WITH_REFERENCE 76 | ctx_deser: detachable JSON_DESERIALIZER_CONTEXT 77 | s: STRING 78 | do 79 | obj := new_cycling_full_team 80 | 81 | create conv_to 82 | create ctx 83 | ctx.use_verbose_reference_identifier 84 | ctx.set_pretty_printing 85 | ctx.register_serializer (create {TEAM_JSON_SERIALIZER}, {TEAM}) 86 | ctx.register_serializer (create {PERSON_JSON_SERIALIZER}, {PERSON}) 87 | ctx.register_serializer (create {PERSON_DETAILS_JSON_SERIALIZER}, {PERSON_DETAILS}) 88 | ctx.set_default_serializer (create {JSON_REFLECTOR_SERIALIZER}) 89 | 90 | s := conv_to.to_json_string (obj, ctx) 91 | 92 | create conv_from 93 | create {JSON_DESERIALIZER_CONTEXT_WITH_REFERENCE} ctx_deser 94 | ctx_deser.set_default_deserializer (create {JSON_REFLECTOR_DESERIALIZER}) 95 | ctx_deser.register_deserializer (create {TEAM_JSON_DESERIALIZER}, {TEAM}) 96 | ctx_deser.register_deserializer (create {PERSON_JSON_DESERIALIZER}, {PERSON}) 97 | ctx_deser.register_deserializer (create {ARRAYED_LIST_JSON_DESERIALIZER [PERSON]}, {ARRAYED_LIST [PERSON]}) 98 | ctx_deser.register_deserializer (create {ARRAYED_LIST_JSON_DESERIALIZER [ENTITY]}, {ARRAYED_LIST [ENTITY]}) 99 | 100 | if attached conv_from.from_json_string (s, ctx_deser, {TEAM}) as o then 101 | assert ("deserialized ok", recursively_one_includes_other (obj, o, Void)) 102 | else 103 | assert ("deserialized ok", False) 104 | end 105 | end 106 | 107 | test_serialization_with_reference 108 | local 109 | obj: TEAM 110 | js: JSON_SERIALIZATION 111 | s,s2: STRING 112 | do 113 | obj := new_cycling_full_team 114 | 115 | create js.make_with_context (create {JSON_SERIALIZATION_CONTEXT_WITH_REFERENCE}) 116 | js.register_default (create {JSON_REFLECTOR_SERIALIZATION}) 117 | js.set_pretty_printing 118 | 119 | 120 | s := js.to_json_string (obj) 121 | assert ("not empty", not s.is_empty) 122 | 123 | if attached js.from_json_string (s, {TEAM}) as o then 124 | -- assert ("deserialized ok", recursively_same_objects (obj, o, Void)) 125 | js.reset 126 | s2 := js.to_json_string (o) 127 | assert ("deserialized ok", s.same_string (s2)) 128 | else 129 | assert ("deserialized failed", js.context.has_deserialization_error) 130 | end 131 | end 132 | 133 | feature -- Factory 134 | 135 | new_cycling_full_team: TEAM 136 | do 137 | Result := new_full_team 138 | if attached Result.owner as o then 139 | o.add_co_worker (Result) 140 | end 141 | end 142 | 143 | end 144 | -------------------------------------------------------------------------------- /library/serialization/deserializer/basic/json_basic_serialization.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "[ 3 | JSON deserializer that convert JSON to standard Eiffel object from EiffelBase. 4 | - JSON object -> STRING_TABLE [detachable ANY] 5 | - JSON array -> ARRAYED_LIST [detachable ANY] 6 | - JSON null -> Void 7 | - JSON string -> STRING_32 8 | - JSON integer -> INTEGER_64 9 | - JSON boolean -> BOOLEAN 10 | - JSON real -> REAL_64 11 | ]" 12 | date: "$Date$" 13 | revision: "$Revision$" 14 | 15 | class 16 | JSON_BASIC_SERIALIZATION 17 | 18 | create 19 | make 20 | 21 | feature {NONE} -- Initialization 22 | 23 | make 24 | local 25 | conv: like serialization 26 | cb: JSON_DESERIALIZER_CREATION_AGENT_CALLBACK 27 | do 28 | create conv 29 | serialization := conv 30 | conv.register_default (create {JSON_CORE_SERIALIZER}) 31 | conv.register_default (create {JSON_BASIC_DESERIALIZER [detachable ANY]}) 32 | 33 | -- Serializers 34 | conv.register (create {TABLE_ITERABLE_JSON_SERIALIZER [detachable ANY, READABLE_STRING_GENERAL]}, {TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]}) 35 | conv.register (create {ITERABLE_JSON_SERIALIZER [detachable ANY]}, {ITERABLE [detachable ANY]}) 36 | 37 | -- Deserializers 38 | conv.register (create {TABLE_JSON_DESERIALIZER [detachable ANY]}, {TABLE [detachable ANY, READABLE_STRING_GENERAL]}) 39 | conv.register (create {LIST_JSON_DESERIALIZER [detachable ANY]}, {LIST [detachable ANY]}) 40 | 41 | create cb.make (agent (inf: JSON_DESERIALIZER_CREATION_INFORMATION) 42 | do 43 | if inf.static_type = Void or inf.static_type = {detachable ANY} then 44 | if attached {JSON_OBJECT} inf.json_value then 45 | inf.set_object (create {STRING_TABLE [detachable ANY]}.make (0)) 46 | elseif attached {JSON_ARRAY} inf.json_value then 47 | inf.set_object (create {ARRAYED_LIST [detachable ANY]}.make (0)) 48 | end 49 | elseif inf.static_type = {STRING_TABLE [detachable ANY]} then 50 | inf.set_object (create {STRING_TABLE [detachable ANY]}.make (0)) 51 | elseif inf.static_type = {ARRAYED_LIST [detachable ANY]} then 52 | inf.set_object (create {ARRAYED_LIST [detachable ANY]}.make (0)) 53 | elseif inf.static_type = {LIST [detachable ANY]} then 54 | inf.set_object (create {ARRAYED_LIST [detachable ANY]}.make (0)) 55 | end 56 | end 57 | ) 58 | conv.context.deserializer_context.set_value_creation_callback (cb) 59 | end 60 | 61 | feature -- Settings change 62 | 63 | set_pretty_printing 64 | -- Generate pretty indented JSON for `to_json_string'. 65 | do 66 | serialization.set_pretty_printing 67 | end 68 | 69 | set_compact_printing 70 | -- Generate compact JSON for `to_json_string'. 71 | do 72 | serialization.set_compact_printing 73 | end 74 | 75 | feature -- Status report 76 | 77 | has_deserialization_error: BOOLEAN 78 | do 79 | Result := serialization.has_deserialization_error 80 | end 81 | 82 | feature -- Conversion to JSON 83 | 84 | to_json (obj: detachable ANY): JSON_VALUE 85 | do 86 | Result := serialization.to_json (obj) 87 | end 88 | 89 | append_to_json_string (obj: detachable ANY; a_output: STRING_GENERAL) 90 | do 91 | serialization.append_to_json_string (obj, a_output) 92 | end 93 | 94 | to_json_string (obj: detachable ANY): STRING 95 | do 96 | Result := serialization.to_json_string (obj) 97 | end 98 | 99 | feature -- Conversion from JSON 100 | 101 | table_from_json_string (a_json_string: STRING): detachable STRING_TABLE [detachable ANY] 102 | do 103 | if attached {like table_from_json_string} from_json_string (a_json_string) as tb then 104 | Result := tb 105 | end 106 | end 107 | 108 | list_from_json_string (a_json_string: STRING): detachable LIST [detachable ANY] 109 | do 110 | if attached {like list_from_json_string} from_json_string (a_json_string) as lst then 111 | Result := lst 112 | end 113 | end 114 | 115 | from_json (a_json: detachable JSON_VALUE): detachable ANY 116 | do 117 | if attached {JSON_OBJECT} a_json then 118 | Result := serialization.from_json (a_json, {STRING_TABLE [detachable ANY]}) 119 | elseif attached {JSON_ARRAY} a_json then 120 | Result := serialization.from_json (a_json, {ARRAYED_LIST [detachable ANY]}) 121 | else 122 | Result := serialization.context.value_from_json (a_json, Void) 123 | end 124 | end 125 | 126 | from_json_string (a_json_string: STRING): detachable ANY 127 | do 128 | Result := from_json (serialization.json_from_string (a_json_string)) 129 | end 130 | 131 | feature {NONE} -- Implementation 132 | 133 | serialization: JSON_SERIALIZATION 134 | 135 | invariant 136 | serialization /= Void 137 | 138 | note 139 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 140 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 141 | end 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/eiffelhub/json.svg?branch=master)](https://travis-ci.org/eiffelhub/json) 2 | 3 | Readme file for eJSON 4 | ===================== 5 | 6 | - team: "Jocelyn Fiat, Javier Velilla" 7 | - previous contributors: "Paul Cohen" 8 | - date: "2018-sept-19" 9 | 10 | ## Introduction 11 | 12 | eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing 13 | with the JSON format. This library provides a JSON parser and visitors, 14 | including a pretty printer. 15 | 16 | The "serialization" interfaces replace the obsolete converters interfaces. 17 | 18 | ## Legal stuff 19 | 20 | eJSON is copyrighted by the authors Jocelyn Fiat, Javier Velilla, and others. It is licensed under the MIT License. See the file license.txt in the same directory as this readme file. 21 | 22 | ## Versioning scheme 23 | 24 | eJSON version numbers has the form: `"major number"."minor number"."patch level" ` 25 | 26 | eJSON will retain the major number 0 as long as it has beta status. A change in major number indicates that a release is not backward compatible. A change in minor number indicates that a release is backward compatible (within that major 27 | number) but that new useful features may have been added. A change in patch level simply indicates that the release contains bug fixes for the previous release. Note that as long as eJSON is in beta status (0.Y.Z) backward compatibility is not guranteed for changes in minor numbers! 28 | 29 | ## Documentation 30 | 31 | Currently the only documentation on eJSON is available at: `https://github.com/eiffelhub/json/blob/master/doc/user_guide.md` 32 | 33 | ## Requirements and installation 34 | 35 | EJSON requires that you have: 36 | 37 | One of the following compiler combinations installed: 38 | * ISE Eiffel 17.05 or later. 39 | * gec [try to test] 40 | 41 | eJSON probably works fine with other versions of the above compilers. 42 | There are no known platform dependencies (Windows, Linux). 43 | 44 | To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate place on your hard disk. There are no requirements on environment variables or registry variables. 45 | Note eJSON is also delivered within EiffelStudio release, under `$ISE_LIBRARY/contrib/library/text/parser/json` 46 | 47 | To verify that everything works you should compile the example programs and/or 48 | the test program. 49 | 50 | ## Contents of eJSON 51 | 52 | All directory names below are relative to the root directory of your ejson installation. 53 | 54 | - doc: Contains documentation file. 55 | - examples: Contains example codes. 56 | - library: Contains the actual eJSON library classes. 57 | - test: Contains test suite for eJSON. 58 | 59 | ## Contacting the Team 60 | 61 | Contact the team: https://github.com/eiffelhub/json/issues 62 | 63 | ## Releases 64 | 65 | ``` 66 | Version Date Description 67 | ------- ---- ----------- 68 | 0.11.0 2019-02-08 REAL NaN, Negative and Positive Infinity values are serialized as "null" 69 | (as JSON has no support for such values). 70 | 0.10.0 2018-11-14 Improved parsing performance (speed and memory). 71 | Allow to change default size for json array and object created during parsing. 72 | 0.9.0 2018-09-19 Added basic serialization 73 | Updated the serialization example to demonstrate the use of custom (de)serializers. 74 | Added JSON_VALUE.chained_item (a_key): JSON_VALUE to be able to access 75 | `json@"person"@"address"@"city"` and return associated JSON value if any, 76 | otherwise JSON_NULL. 77 | 78 | 0.8.0 2018-09-13 Ensure the `JSON_STRING`.item is really UTF-8 encoded (even for characters between 128 and 255)! 79 | Properly encode null character as \u0000 . 80 | Unescape escaped unicode in unescape_to_string_8 when it represents a valid `CHARACTER_8` value. 81 | Fixed parsing of integer 64 value 82 | 0.7.1 2017-03-20 Added `JSON_VALUE.is_string` ... `is_null` boolean query for convenience. 83 | 0.7.1 2017-03-20 Added `JSON_VALUE.is_string` ... `is_null` boolean query for convenience. 84 | 0.7.0 2016-08-01 New JSON serialization implementation (to replace the obsolete converters). 85 | 0.6.0 2014-11-17 Fixed various issue with parsing string (such as \t and related), 86 | Implemented escaping of slash '/' only in case of ' 88 | Many feature renaming to match Eiffel style and naming convention, 89 | kept previous feature as obsolete. 90 | Restructured the library to make easy extraction of "converter" 91 | classes if needed in the future. 92 | Marked converters classes as obsolete. 93 | 0.5.0 2013-11-31 Added `JSON_ITERATOR`, simplified `JSON_OBJECT` 94 | 0.4.0 2012-12-12 Updated documentation URI 95 | 0.3.0 2011-07-06 JSON Factory Converters 96 | 0.2.0 2010-02-07 Adapted to EiffelStudio 6.4 or later, supports void-safety 97 | 0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous 98 | ``` 99 | 100 | -------------------------------------------------------------------------------- /library/kernel/json_number.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Numbers, octal and hexadecimal formats are not used." 3 | author: "$Author$" 4 | date: "$Date$" 5 | revision: "$Revision$" 6 | license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" 7 | 8 | class 9 | JSON_NUMBER 10 | 11 | inherit 12 | JSON_VALUE 13 | redefine 14 | is_equal, 15 | is_number 16 | end 17 | 18 | create 19 | make_integer, make_natural, make_real 20 | 21 | feature {NONE} -- initialization 22 | 23 | make_integer (an_argument: INTEGER_64) 24 | -- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'. 25 | do 26 | item := an_argument.out 27 | numeric_type := integer_type 28 | end 29 | 30 | make_natural (an_argument: NATURAL_64) 31 | -- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'. 32 | do 33 | item := an_argument.out 34 | numeric_type := natural_type 35 | end 36 | 37 | make_real (an_argument: REAL_64) 38 | -- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'. 39 | do 40 | if an_argument.is_nan then 41 | item := nan_real_value 42 | elseif an_argument.is_negative_infinity then 43 | item := negative_infinity_real_value 44 | elseif an_argument.is_positive_infinity then 45 | item := positive_infinity_real_value 46 | else 47 | item := an_argument.out 48 | end 49 | numeric_type := double_type 50 | end 51 | 52 | feature -- Status report 53 | 54 | is_number: BOOLEAN = True 55 | -- 56 | 57 | feature {NONE} -- REAL constants 58 | 59 | nan_real_value: IMMUTABLE_STRING_8 60 | once 61 | create Result.make_from_string ("NaN") 62 | end 63 | 64 | negative_infinity_real_value: IMMUTABLE_STRING_8 65 | once 66 | create Result.make_from_string ("-Infinity") 67 | end 68 | 69 | positive_infinity_real_value: IMMUTABLE_STRING_8 70 | once 71 | create Result.make_from_string ("Infinity") 72 | end 73 | 74 | feature -- Access 75 | 76 | item: READABLE_STRING_8 77 | -- Content 78 | 79 | numeric_type: INTEGER 80 | -- Type of number (integer, natural or real). 81 | 82 | hash_code: INTEGER 83 | --Hash code value 84 | do 85 | Result := item.hash_code 86 | end 87 | 88 | representation: STRING 89 | local 90 | l_item: like item 91 | do 92 | l_item := item 93 | if 94 | is_real and then 95 | ( 96 | l_item = nan_real_value or else 97 | l_item = negative_infinity_real_value or else 98 | l_item = positive_infinity_real_value 99 | ) 100 | then 101 | Result := {JSON_NULL}.representation 102 | else 103 | Result := l_item.to_string_8 104 | end 105 | end 106 | 107 | feature -- Conversion 108 | 109 | integer_64_item: INTEGER_64 110 | -- Associated integer value. 111 | require 112 | is_integer: is_integer 113 | do 114 | Result := item.to_integer_64 115 | end 116 | 117 | natural_64_item: NATURAL_64 118 | -- Associated natural value. 119 | require 120 | is_natural: is_natural 121 | do 122 | Result := item.to_natural_64 123 | end 124 | 125 | double_item, real_64_item: REAL_64 126 | -- Associated real value. 127 | require 128 | is_real: is_real 129 | do 130 | if item = nan_real_value then 131 | Result := {REAL_64}.nan 132 | elseif item = negative_infinity_real_value then 133 | Result := {REAL_64}.negative_infinity 134 | elseif item = positive_infinity_real_value then 135 | Result := {REAL_64}.positive_infinity 136 | else 137 | Result := item.to_real_64 138 | end 139 | end 140 | 141 | feature -- Status report 142 | 143 | is_integer: BOOLEAN 144 | -- Is Current an integer number? 145 | do 146 | Result := numeric_type = integer_type 147 | end 148 | 149 | is_natural: BOOLEAN 150 | -- Is Current a natural number? 151 | do 152 | Result := numeric_type = natural_type 153 | end 154 | 155 | is_double, is_real: BOOLEAN 156 | -- Is Current a real number? 157 | do 158 | Result := numeric_type = real_type 159 | end 160 | 161 | feature -- Visitor pattern 162 | 163 | accept (a_visitor: JSON_VISITOR) 164 | -- Accept `a_visitor'. 165 | -- (Call `visit_json_number' procedure on `a_visitor'.) 166 | do 167 | a_visitor.visit_json_number (Current) 168 | end 169 | 170 | feature -- Status 171 | 172 | is_equal (other: like Current): BOOLEAN 173 | -- Is `other' attached to an object of the same type 174 | -- as current object and identical to it? 175 | do 176 | Result := item.is_equal (other.item) 177 | end 178 | 179 | feature -- Status report 180 | 181 | debug_output: STRING 182 | -- String that should be displayed in debugger to represent `Current'. 183 | do 184 | Result := item.to_string_8 185 | end 186 | 187 | feature -- Implementation 188 | 189 | integer_type: INTEGER = 1 190 | 191 | double_type, real_type: INTEGER = 2 192 | 193 | natural_type: INTEGER = 3 194 | 195 | invariant 196 | item_not_void: attached item as inv_item 197 | nan_only_for_real: inv_item.is_case_insensitive_equal_general (nan_real_value) implies is_real 198 | neg_inf_only_for_real: inv_item.is_case_insensitive_equal_general (negative_infinity_real_value) implies is_real 199 | inf_only_for_real: inv_item.is_case_insensitive_equal_general (positive_infinity_real_value) implies is_real 200 | 201 | note 202 | copyright: "2010-2019, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 203 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 204 | end 205 | -------------------------------------------------------------------------------- /library/utility/visitor/json_pretty_string_visitor.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON_PRETTY_STRING_VISITOR Generates the JSON-String for a JSON_VALUE" 3 | revision: "0.1" 4 | 5 | class 6 | JSON_PRETTY_STRING_VISITOR 7 | 8 | inherit 9 | 10 | JSON_VISITOR 11 | 12 | create 13 | make, 14 | make_custom 15 | 16 | feature -- Initialization 17 | 18 | make (a_output: like output) 19 | -- Create a new instance 20 | do 21 | make_custom (a_output, 1, 1) 22 | end 23 | 24 | make_custom (a_output: like output; a_object_count_inlining, a_array_count_inlining: INTEGER) 25 | -- Create a new instance 26 | do 27 | output := a_output 28 | create indentation.make_empty 29 | indentation_step := "%T" 30 | object_count_inlining := a_object_count_inlining 31 | array_count_inlining := a_array_count_inlining 32 | end 33 | 34 | feature -- Access 35 | 36 | output: STRING_GENERAL 37 | -- JSON representation 38 | 39 | feature -- Settings 40 | 41 | indentation_step: STRING 42 | -- Text used for indentation. 43 | --| by default a tabulation "%T" 44 | 45 | object_count_inlining: INTEGER 46 | -- Inline where object item count is under `object_count_inlining'. 47 | --| ex 3: 48 | --| { "a", "b", "c" } 49 | --| ex 2: 50 | --| { 51 | --| "a", 52 | --| "b", 53 | --| "c" 54 | --| } 55 | 56 | array_count_inlining: INTEGER 57 | -- Inline where array item count is under `object_count_inlining'. 58 | 59 | feature -- Element change 60 | 61 | set_indentation_step (a_step: STRING) 62 | -- Set `indentation_step' to `a_step'. 63 | do 64 | indentation_step := a_step 65 | end 66 | 67 | set_object_count_inlining (a_nb: INTEGER) 68 | -- Set `object_count_inlining' to `a_nb'. 69 | do 70 | object_count_inlining := a_nb 71 | end 72 | 73 | set_array_count_inlining (a_nb: INTEGER) 74 | -- Set `array_count_inlining' to `a_nb'. 75 | do 76 | array_count_inlining := a_nb 77 | end 78 | 79 | feature {NONE} -- Implementation 80 | 81 | indentation: STRING 82 | 83 | indent 84 | do 85 | indentation.append (indentation_step) 86 | end 87 | 88 | exdent 89 | do 90 | indentation.remove_tail (indentation_step.count) 91 | end 92 | 93 | new_line 94 | do 95 | output.append ("%N") 96 | output.append (indentation) 97 | line_number := line_number + 1 98 | end 99 | 100 | line_number: INTEGER 101 | 102 | feature -- Visitor Pattern 103 | 104 | visit_json_array (a_json_array: JSON_ARRAY) 105 | -- Visit `a_json_array'. 106 | local 107 | value: JSON_VALUE 108 | l_json_array: ARRAYED_LIST [JSON_VALUE] 109 | l_line: like line_number 110 | l_multiple_lines: BOOLEAN 111 | l_output: like output 112 | do 113 | l_output := output 114 | l_json_array := a_json_array.array_representation 115 | l_multiple_lines := l_json_array.count >= array_count_inlining 116 | or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end 117 | l_output.append_code (91) -- '[' : 91 118 | 119 | l_line := line_number 120 | indent 121 | from 122 | l_json_array.start 123 | until 124 | l_json_array.off 125 | loop 126 | if line_number > l_line or l_multiple_lines then 127 | new_line 128 | end 129 | value := l_json_array.item 130 | value.accept (Current) 131 | l_json_array.forth 132 | if not l_json_array.after then 133 | l_output.append (", ") 134 | end 135 | end 136 | exdent 137 | if line_number > l_line or l_json_array.count >= array_count_inlining then 138 | new_line 139 | end 140 | l_output.append_code (93) -- ']' : 93 141 | end 142 | 143 | visit_json_boolean (a_json_boolean: JSON_BOOLEAN) 144 | -- Visit `a_json_boolean'. 145 | do 146 | if a_json_boolean.item then 147 | output.append ("true") 148 | else 149 | output.append ("false") 150 | end 151 | end 152 | 153 | visit_json_null (a_json_null: JSON_NULL) 154 | -- Visit `a_json_null'. 155 | do 156 | output.append ("null") 157 | end 158 | 159 | visit_json_number (a_json_number: JSON_NUMBER) 160 | -- Visit `a_json_number'. 161 | do 162 | output.append (a_json_number.item) 163 | end 164 | 165 | visit_json_object (a_json_object: JSON_OBJECT) 166 | -- Visit `a_json_object'. 167 | local 168 | l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING] 169 | l_line: like line_number 170 | l_multiple_lines: BOOLEAN 171 | l_output: like output 172 | do 173 | l_output := output 174 | l_pairs := a_json_object.map_representation 175 | l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end 176 | l_output.append_code (123) -- '{' : 123 177 | l_line := line_number 178 | indent 179 | from 180 | l_pairs.start 181 | until 182 | l_pairs.off 183 | loop 184 | if line_number > l_line or l_multiple_lines then 185 | new_line 186 | end 187 | l_pairs.key_for_iteration.accept (Current) 188 | l_output.append (": ") 189 | l_pairs.item_for_iteration.accept (Current) 190 | l_pairs.forth 191 | if not l_pairs.after then 192 | l_output.append (", ") 193 | end 194 | end 195 | exdent 196 | if line_number > l_line or l_pairs.count >= object_count_inlining then 197 | new_line 198 | end 199 | l_output.append_code (125) -- '}' : 125 200 | end 201 | 202 | visit_json_string (a_json_string: JSON_STRING) 203 | -- Visit `a_json_string'. 204 | local 205 | l_output: like output 206 | do 207 | l_output := output 208 | l_output.append_code (34) -- '%"' : 34 209 | l_output.append (a_json_string.item) 210 | l_output.append_code (34) -- '%"' : 34 211 | end 212 | 213 | note 214 | copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json." 215 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 216 | end 217 | -------------------------------------------------------------------------------- /library/serialization/serializer/json_reflector_serializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON Serialization based on reflection mechanism." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_REFLECTOR_SERIALIZER 8 | 9 | inherit 10 | JSON_CORE_SERIALIZER 11 | redefine 12 | reference_to_json 13 | end 14 | 15 | JSON_TYPE_UTILITIES 16 | 17 | feature -- Constants 18 | 19 | type_field_name: STRING = "$TYPE" 20 | -- Field name related to type name information. 21 | 22 | feature {NONE} -- Implementation 23 | 24 | reference_to_json (obj: detachable ANY; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 25 | local 26 | i: INTEGER 27 | l_fields_count: INTEGER 28 | l_type_name: READABLE_STRING_8 29 | refl_obj: REFLECTED_REFERENCE_OBJECT 30 | j_object: JSON_OBJECT 31 | j_array: JSON_ARRAY 32 | fn: STRING_32 33 | do 34 | Result := Precursor (obj, ctx) 35 | if Result.is_null and obj /= Void then 36 | check 37 | is_accepted_object: ctx.is_accepted_object (obj) 38 | end 39 | if attached ctx.to_json (obj, Current) as j then 40 | Result := j 41 | else 42 | create refl_obj.make (obj) 43 | ctx.on_object_serialization_start (obj) -- To declare this object is being processed. 44 | if refl_obj.is_special and then attached {SPECIAL [detachable ANY]} obj as l_special then 45 | -- Handle SPECIAL classes 46 | create j_array.make (l_special.count) 47 | Result := j_array 48 | i := 1 49 | across 50 | l_special as ic 51 | loop 52 | fn := i.out 53 | ctx.on_field_start (fn) 54 | j_array.add (to_json (ic.item, ctx)) 55 | ctx.on_field_end (fn) 56 | i := i + 1 57 | end 58 | else 59 | -- Eiffel object. 60 | l_type_name := refl_obj.type_name 61 | 62 | l_fields_count := refl_obj.field_count 63 | 64 | if ctx.is_type_name_included then 65 | create j_object.make_with_capacity (1 + l_fields_count) 66 | j_object.put_string (l_type_name, type_field_name) 67 | else 68 | create j_object.make_with_capacity (l_fields_count) 69 | end 70 | if l_fields_count > 0 then 71 | from 72 | i := 1 73 | until 74 | i > l_fields_count 75 | loop 76 | if 77 | not refl_obj.is_field_transient (i) and then 78 | attached refl_obj.field_name (i) as l_field_name 79 | then 80 | j_object.put (field_to_json (refl_obj, i, l_field_name, ctx), l_field_name) 81 | end 82 | i := i + 1 83 | end 84 | end 85 | Result := j_object 86 | end 87 | ctx.on_object_serialization_end (Result, obj) 88 | end 89 | end 90 | end 91 | 92 | field_to_json (a_reflected_object: REFLECTED_REFERENCE_OBJECT; i: INTEGER; a_field_name: READABLE_STRING_8; ctx: JSON_SERIALIZER_CONTEXT): JSON_VALUE 93 | local 94 | l_field_value: detachable ANY 95 | do 96 | inspect a_reflected_object.field_type (i) 97 | when {REFLECTOR_CONSTANTS}.boolean_type then 98 | create {JSON_BOOLEAN} Result.make (a_reflected_object.boolean_field (i)) 99 | 100 | when {REFLECTOR_CONSTANTS}.character_8_type then 101 | create {JSON_STRING} Result.make_from_string (create {STRING_8}.make_filled (a_reflected_object.character_8_field (i), 1)) 102 | when {REFLECTOR_CONSTANTS}.character_32_type then 103 | create {JSON_STRING} Result.make_from_string_32 (create {STRING_32}.make_filled (a_reflected_object.character_32_field (i), 1)) 104 | 105 | when {REFLECTOR_CONSTANTS}.natural_8_type then 106 | create {JSON_NUMBER} Result.make_natural (a_reflected_object.natural_8_field (i)) 107 | when {REFLECTOR_CONSTANTS}.natural_16_type then 108 | create {JSON_NUMBER} Result.make_natural (a_reflected_object.natural_16_field (i)) 109 | when {REFLECTOR_CONSTANTS}.natural_32_type then 110 | create {JSON_NUMBER} Result.make_natural (a_reflected_object.natural_32_field (i)) 111 | when {REFLECTOR_CONSTANTS}.natural_64_type then 112 | create {JSON_NUMBER} Result.make_natural (a_reflected_object.natural_64_field (i)) 113 | 114 | when {REFLECTOR_CONSTANTS}.integer_8_type then 115 | create {JSON_NUMBER} Result.make_integer (a_reflected_object.integer_8_field (i)) 116 | when {REFLECTOR_CONSTANTS}.integer_16_type then 117 | create {JSON_NUMBER} Result.make_integer (a_reflected_object.integer_16_field (i)) 118 | when {REFLECTOR_CONSTANTS}.integer_32_type then 119 | create {JSON_NUMBER} Result.make_integer (a_reflected_object.integer_32_field (i)) 120 | when {REFLECTOR_CONSTANTS}.integer_64_type then 121 | create {JSON_NUMBER} Result.make_integer (a_reflected_object.integer_64_field (i)) 122 | 123 | when {REFLECTOR_CONSTANTS}.real_32_type then 124 | create {JSON_NUMBER} Result.make_real (a_reflected_object.real_32_field (i)) 125 | 126 | when {REFLECTOR_CONSTANTS}.real_64_type then 127 | create {JSON_NUMBER} Result.make_real (a_reflected_object.real_64_field (i)) 128 | 129 | when {REFLECTOR_CONSTANTS}.pointer_type then 130 | -- Check! 131 | create {JSON_NUMBER} Result.make_integer (a_reflected_object.pointer_field (i).to_integer_32) 132 | 133 | when {REFLECTOR_CONSTANTS}.reference_type then 134 | l_field_value := a_reflected_object.reference_field (i) 135 | ctx.on_field_start (a_field_name) 136 | Result := reference_to_json (l_field_value, ctx) 137 | ctx.on_field_end (a_field_name) 138 | when {REFLECTOR_CONSTANTS}.expanded_type then 139 | if attached a_reflected_object.expanded_field (i) as exp_ref_object then 140 | ctx.on_field_start (a_field_name) 141 | -- FIXME: check how to best handle expanded! 142 | Result := reference_to_json (exp_ref_object.object, ctx) 143 | ctx.on_field_end (a_field_name) 144 | else 145 | check is_exoanded: False end 146 | create {JSON_NULL} Result 147 | end 148 | else 149 | check known_field_type: False end 150 | Result := to_json (a_reflected_object.field (i), ctx) 151 | end 152 | end 153 | 154 | note 155 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 156 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 157 | end 158 | -------------------------------------------------------------------------------- /library/serialization/deserializer/json_core_deserializer.e: -------------------------------------------------------------------------------- 1 | note 2 | description: "JSON deserializer for basic type." 3 | date: "$Date$" 4 | revision: "$Revision$" 5 | 6 | class 7 | JSON_CORE_DESERIALIZER 8 | 9 | inherit 10 | JSON_DESERIALIZER 11 | 12 | feature -- Conversion 13 | 14 | from_json (a_json: detachable JSON_VALUE; ctx: JSON_DESERIALIZER_CONTEXT; a_type: detachable TYPE [detachable ANY]): detachable ANY 15 | do 16 | if attached {JSON_STRING} a_json as s then 17 | Result := string_from_json (s, a_type) 18 | elseif attached {JSON_BOOLEAN} a_json as b then 19 | Result := boolean_from_json (b) 20 | elseif attached {JSON_NULL} a_json then 21 | Result := Void 22 | elseif attached {JSON_NUMBER} a_json as n then 23 | Result := number_from_json (n, a_type) 24 | end 25 | if ctx.has_error then 26 | Result := Void 27 | end 28 | end 29 | 30 | feature {NONE} -- Helpers: Basic values 31 | 32 | boolean_from_json (v: JSON_VALUE): BOOLEAN 33 | do 34 | if attached {JSON_BOOLEAN} v as b then 35 | Result := b.item 36 | elseif attached {JSON_STRING} v as s then 37 | Result := s.item.is_case_insensitive_equal_general ("true") 38 | else 39 | check is_boolean: False end 40 | end 41 | end 42 | 43 | number_from_json (v: JSON_VALUE; a_type: detachable TYPE [detachable ANY]): detachable ANY 44 | local 45 | i64: INTEGER_64 46 | n64: NATURAL_64 47 | do 48 | if attached {JSON_NUMBER} v as l_number then 49 | if a_type = Void or else not a_type.conforms_to ({detachable NUMERIC}) then 50 | if l_number.is_integer then 51 | i64 := l_number.integer_64_item 52 | if {INTEGER_8}.min_value <= i64 and i64 <= {INTEGER_8}.max_value then 53 | Result := i64.as_integer_8 54 | elseif {INTEGER_16}.min_value <= i64 and i64 <= {INTEGER_16}.max_value then 55 | Result := i64.as_integer_16 56 | elseif {INTEGER_32}.min_value <= i64 and i64 <= {INTEGER_32}.max_value then 57 | Result := i64.as_integer_32 58 | else 59 | Result := i64 60 | end 61 | elseif l_number.is_natural then 62 | n64 := l_number.natural_64_item 63 | if n64 <= {NATURAL_8}.max_value then 64 | Result := n64.as_natural_8 65 | elseif n64 <= {NATURAL_16}.max_value then 66 | Result := n64.as_natural_16 67 | elseif n64 <= {NATURAL_32}.max_value then 68 | Result := n64.as_natural_32 69 | else 70 | Result := n64 71 | end 72 | elseif l_number.is_real then 73 | -- Do not truncate! 74 | Result := l_number.real_64_item 75 | else 76 | Result := l_number.integer_64_item 77 | end 78 | elseif a_type = {INTEGER_8} then 79 | Result := l_number.integer_64_item.to_integer_8 80 | elseif a_type = {INTEGER_16} then 81 | Result := l_number.integer_64_item.to_integer_16 82 | elseif a_type = {INTEGER_32} then 83 | Result := l_number.integer_64_item.to_integer_32 84 | elseif a_type = {INTEGER_64} then 85 | Result := l_number.integer_64_item 86 | elseif a_type = {NATURAL_8} then 87 | Result := l_number.natural_64_item.to_natural_8 88 | elseif a_type = {NATURAL_16} then 89 | Result := l_number.natural_64_item.to_natural_16 90 | elseif a_type = {NATURAL_32} then 91 | Result := l_number.natural_64_item.to_natural_32 92 | elseif a_type = {NATURAL_64} then 93 | Result := l_number.natural_64_item 94 | elseif a_type = {REAL_32} then 95 | Result := l_number.natural_64_item.to_real_32 96 | elseif a_type = {REAL_64} then 97 | Result := l_number.natural_64_item 98 | else 99 | Result := l_number.integer_64_item 100 | end 101 | end 102 | end 103 | 104 | integer_from_json (v: JSON_VALUE): INTEGER_64 105 | do 106 | if attached {JSON_NUMBER} v as n then 107 | Result := n.integer_64_item 108 | elseif attached {JSON_STRING} v as s then 109 | if s.item.is_integer_64 then 110 | Result := s.item.to_integer_64 111 | end 112 | else 113 | check is_integer: False end 114 | end 115 | end 116 | 117 | natural_from_json (v: JSON_VALUE): NATURAL_64 118 | do 119 | if attached {JSON_NUMBER} v as n then 120 | Result := n.natural_64_item 121 | elseif attached {JSON_STRING} v as s then 122 | if s.item.is_natural_64 then 123 | Result := s.item.to_natural_64 124 | end 125 | else 126 | check is_natural: False end 127 | end 128 | end 129 | 130 | real_from_json (v: JSON_VALUE): REAL_64 131 | do 132 | if attached {JSON_NUMBER} v as n then 133 | Result := n.real_64_item 134 | else 135 | check is_real: False end 136 | end 137 | end 138 | 139 | string_from_json (v: JSON_VALUE; a_static_type: detachable TYPE [detachable ANY]): detachable READABLE_STRING_GENERAL 140 | do 141 | if attached {JSON_STRING} v as s then 142 | if a_static_type /= Void then 143 | Result := string_converted_to_type (s.unescaped_string_32, a_static_type) 144 | else 145 | Result := s.unescaped_string_32 146 | end 147 | else 148 | check is_string: False end 149 | end 150 | end 151 | 152 | feature {NONE} -- Implementation 153 | 154 | string_converted_to_type (str: READABLE_STRING_GENERAL; a_static_type: TYPE [detachable ANY]): detachable READABLE_STRING_GENERAL 155 | local 156 | utf_conv: UTF_CONVERTER 157 | do 158 | if a_static_type.conforms_to (str.generating_type) then 159 | Result := str 160 | elseif 161 | a_static_type = {STRING_32} or a_static_type = {detachable STRING_32} 162 | or a_static_type = {READABLE_STRING_32} or a_static_type = {detachable READABLE_STRING_32} 163 | then 164 | create {STRING_32} Result.make_from_string_general (str) 165 | elseif 166 | a_static_type = {STRING_8} or a_static_type = {detachable STRING_8} 167 | or a_static_type = {READABLE_STRING_8} or a_static_type = {detachable READABLE_STRING_8} 168 | then 169 | create {STRING_8} Result.make_from_string (utf_conv.utf_32_string_to_utf_8_string_8 (str)) 170 | 171 | elseif a_static_type = {IMMUTABLE_STRING_32} or a_static_type = {detachable IMMUTABLE_STRING_32} then 172 | create {IMMUTABLE_STRING_32} Result.make_from_string_general (str) 173 | elseif a_static_type = {IMMUTABLE_STRING_8} or a_static_type = {detachable IMMUTABLE_STRING_8} then 174 | create {IMMUTABLE_STRING_8} Result.make_from_string (utf_conv.utf_32_string_to_utf_8_string_8 (str)) 175 | 176 | else 177 | check known_type: False end 178 | Result := str 179 | end 180 | end 181 | 182 | note 183 | copyright: "2010-2018, Javier Velilla, Jocelyn Fiat, Eiffel Software and others https://github.com/eiffelhub/json." 184 | license: "https://github.com/eiffelhub/json/blob/master/License.txt" 185 | end 186 | --------------------------------------------------------------------------------