PMJSON provides a pure-Swift strongly-typed JSON encoder/decoder

Related tags

JSON swift json library
Overview

Now Archived and Forked

PMJSON will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork of PMJSON located here.

PMJSON

Version Platforms Languages License Carthage compatible CocoaPods

PMJSON provides a pure-Swift strongly-typed JSON encoder/decoder as well as a set of convenience methods for converting to/from Foundation objects and for decoding JSON structures.

The entire JSON encoder/decoder can be used without Foundation, by removing the files ObjectiveC.swift and DecimalNumber.swift from the project. The only dependency the rest of the project has is on Darwin, for strtod() and strtoll(). The file ObjectiveC.swift adds convenience methods for translating between JSON values and Foundation objects as well as decoding from a Data, and DecimalNumber.swift adds convenience accessors for converting values into NSDecimalNumber.

Usage

Before diving into the details, here's a simple example of writing a decoder for a struct. There are a few different options for how to deal with malformed data (e.g. whether to ignore values of wrong types, and whether to try and coerce non-string values to strings or vice versa), but the following example will be fairly strict and throw an error for incorrectly-typed values:

struct Address {
    var streetLine1: String
    var streetLine2: String?
    var city: String
    var state: String?
    var postalCode: String
    var country: String?

    init(json: JSON) throws {
        streetLine1 = try json.getString("street_line1")
        streetLine2 = try json.getStringOrNil("street_line2")
        city = try json.getString("city")
        state = try json.getStringOrNil("state")
        postalCode = try json.toString("postal_code") // coerce numbers to strings
        country = try json.getStringOrNil("country")
    }
}

And here's an example of decoding a nested array of values:

struct Person {
    var firstName: String
    var lastName: String? // some people don't have last names
    var age: Int
    var addresses: [Address]

    init(json: JSON) throws {
        firstName = try json.getString("firstName")
        lastName = try json.getStringOrNil("lastName")
        age = try json.getInt("age")
        addresses = try json.mapArray("addresses", Address.init(json:))
    }
}

If you don't want to deal with errors and just want to handle optionals, you can do that too:

struct Config {
    var name: String?
    var doThatThing: Bool
    var maxRetries: Int
    
    init(json: JSON) {
        name = json["name"]?.string
        doThatThing = json["doThatThing"]?.bool ?? false
        maxRetries = json["maxRetries"]?.int ?? 10
    }
}

This library also provides support for Swift.Encoder and Swift.Decoder. See this section for details.

Parsing

The JSON decoder is split into separate parser and decoder stages. The parser consums any sequence of unicode scalars, and produces a sequence of JSON "events" (similar to a SAX XML parser). The decoder accepts a sequence of JSON events and produces a JSON value. This architecture is designed such that you can use just the parser alone in order to decode directly to your own data structures and bypass the JSON representation entirely if desired. However, most clients are expected to use both components, and this is exposed via a simple method JSON.decode(_:options:).

Parsing a JSON string into a JSON value is as simple as:

let json = try JSON.decode(jsonString)

Any errors in the JSON parser are represented as JSONParserError values and are thrown from the decode() method. The error contains the precise line and column of the error, and a code that describes the problem.

A convenience method is also provided for decoding from a Data containing data encoded as UTF-8, UTF-16, or UTF-32:

let json = try JSON.decode(data)

Encoding a JSON value is also simple:

let jsonString = JSON.encodeAsString(json)

You can also encode directly to any TextOutputStream:

JSON.encode(json, toStream: &output)

And, again, a convenience method is provided for working with Data:

let data = JSON.encodeAsData(json)

JSON Streams

PMJSON supports parsing JSON streams, which are multiple top-level JSON values with optional whitespace delimiters (such as {"a": 1}{"a": 2}). The easiest way to use this is with JSON.decodeStream(_:) which returns a lazy sequence of JSONStreamValues, which contain either a JSON value or a JSONParserError error. You can also use JSONParsers and JSONDecoders directly for more fine-grained control over streaming.

JSONParser and JSONDecoder

As mentioned above, the JSON decoder is split into separate parser and decoder stages. JSONParser is the parser stage, and it wraps any sequence of UnicodeScalars, and itself is a sequence of JSONEvents. A JSONEvent is a single step of JSON parsing, such as .objectStart when a { is encountered, or .stringValue(_) when a "string" is encountered. You can use JSONParser directly to emit a stream of events if you want to do any kind of lazy processing of JSON (such as if you're dealing with a single massive JSON blob and don't want to decode the whole thing into memory at once).

Similarly, JSONDecoder is the decoder stage. It wraps a sequence of JSONEvents, and decodes that sequence into a proper JSON value. The wrapped sequence must also conform to a separate protocol JSONEventIterator that provides line/column information, which are used when emitting errors. You can use JSONDecoder directly if you want to wrap a sequence of events other than JSONParser, or if you want a different interface to JSON stream decoding than JSONStreamDecoder provides.

Because of this split nature, you can easily provide your own event stream, or your own decoding stage. Or you can do things like wrap JSONParser in an adaptor that modfiies the events before passing them to the decoder (which may be more efficient than converting the resulting JSON value).

Accessors

Besides encoding/decoding, this library also provides a comprehensive suite of accessors for getting data out of JSON values. There are 4 types of basic accessors provided:

  1. Basic property accessors named after types such as .string. These accessors return the underlying value if it matches the type, or nil if the value is not the right type. For example, .string returns String?. These accessors do not convert between types, e.g. JSON.Int64(42).string returns nil.
  2. Property accessors beginning with the word as, such as .asString. These accessors also return an optional value, but they convert between types if it makes sense to do so. For example, JSON.Int64(42).asString returns "42".
  3. Methods beginnning with get, such as getString(). These methods return non-optional values, and throw JSONErrors if the value's type does not match. These methods do not convert between types, e.g. try JSON.Int64(42).getString() throws an error. For every method of this type, there's also a variant ending in OrNil, such as getStringOrNil(), which does return an optional. These methods only return nil if the value is null, otherwise they throw an error.
  4. Methods beginning with to, such as toString(). These are just like the get methods except they convert between types when appropriate, using the same rules that the as methods do, e.g. try JSON.Int64(42).toString() returns "42". Like the get methods, there are also variants ending in OrNil.

JSON also provides both keyed and indexed subscript operators that return a JSON?, and are always safe to call (even with out-of-bounds indexes). And it provides 2 kinds of subscripting accessors:

  1. For every basic get accessor, there's a variant that takes a key or an index. These are equivalent to subscripting the receiver and invoking the get accessor on the result, except they produce better errors (and they handle missing keys/out-of-bounds indexes properly). For example, getString("key") or getString(index). The OrNil variants also return nil if the key doesn't exist or the index is out-of-bounds.
  2. Similarly, there are subscripting equivalents for the to accessors as well.

And finally, the getObject() and getArray() accessors provide variants that take a closure. These variants are recommended over the basic accessors as they produce better errors. For example, given the following JSON:

{
  "object": {
    "elements": [
      {
        "name": null
      }
    ]
  }
}

And the following code:

try json.getObject("object").getArray("elements").getObject(0).getString("name")

The error thrown by this code will have the description "name: expected string, found null".

But given the following equivalent code:

try json.getObject("object", { try $0.getArray("elements", { try $0.getObject(0, { try $0.getString("name") }) }) })

The error thrown by this code will have the description "object.elements[0].name: expected string, found null".

All of these accessors are also available on the JSONObject type (which is the type that represents an object).

The last code snippet above looks very verbose, but in practice you don't end up writing code like that. Instead you'll often end up just writing things like

try json.mapArray("elements", Element.init(json:))

Helpers

The JSON type has static methods map(), flatMap(), and compactMap() for working with arrays (since PMJSON does not define its own array type). The benefit of using these methods over using the equivalent SequenceType methods is the PMJSON static methods produce better errors.

There are also helpers for converting to/from Foundation objects. JSON offers an initializer init(ns: Any) throws that converts from any JSON-compatible object to a JSON. JSON and JSONObject both offer the property .ns, which returns a Foundation object equivalent to the JSON, and .nsNoNull which does the same but omits any null values instead of using NSNull.

Codable support

The JSON type conforms to Codable, so it can be encoded to a Swift.Encoder and decoded from a Swift.Decoder. This has been tested against the standard library-provided JSONEncoder and JSONDecoder. Due to limitations in the decoding protocol, decoding a JSON must attempt to decode multiple different types of values, so it's possible that a poorly-written Swift.Decoder may produce surprising results when decoding a JSON.

Encoding to a JSON.Encoder and decoding from a JSON.Decoder is optimized to avoid unnecessary work.

Swift.Encoder and Swift.Decoder

This library provides an implementation of Swift.Encoder called JSON.Encoder. This can encode any Encodable to a JSON, a String, or a Data. It's used similarly to Swift.JSONEncoder (except at this time it doesn't have options to control encoding of specific types).

This library provides an implementation of Swift.Decoder called JSON.Decoder. This can decode any Decodable from a JSON, a String, or a Data. It's used similar to Swift.JSONDecoder (except at this time it doesn't have options to control decoding of specific types).

Performance

The test suite includes some basic performance tests. Decoding ~70KiB of JSON using PMJSON takes about 2.5-3x the time that NSJSONSerialization does, though I haven't tested this with different distributions of inputs and it's possible this performance is specific to the characteristics of the test input. However, encoding the same JSON back to a Data is actually faster with PMJSON, taking around 75% of the time that NSJSONSerialization does. These benchmarks were performed with Swift 2.x and it's possible the numbers have changed since then.

Requirements

Installing as a framework requires a minimum of iOS 8, OS X 10.9, watchOS 2.0, or tvOS 9.0.

Installation

After installing with any mechanism, you can use this by adding import PMJSON to your code.

Swift Package Manager

The Swift Package Manager may be used to install PMJSON by adding it to your dependencies list:

let package = Package(
    name: "YourPackage",
    dependencies: [
        .package(url: "https://github.com/postmates/PMJSON.git", from: "3.0.1")
    ]
)

Carthage

To install using Carthage, add the following to your Cartfile:

3.0 ">
github "postmates/PMJSON" ~> 3.0

This release supports Swift 4. If you want Swift 3.x support, you can use

2.0 ">
github "postmates/PMJSON" ~> 2.0

CocoaPods

To install using CocoaPods, add the following to your Podfile:

pod 'PMJSON', '~> 3.0'

This release supports Swift 4. If you want Swift 3.x support, you can use

pod 'PMJSON', '~> 2.0'

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

Version History

v4.0.0 (2019-11-14)

  • Update to Swift 5.
  • When encoding/decoding URLs with JSON.Encoder and JSON.Decoder, encode and decode their absolute string instead of relying on the native implementation which encodes them as an object. This matches the behavior of JSONEncoder and JSONDecoder.
  • Fix availability attribute for JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds.
  • Bump JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds and JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds to iOS 11.2+ and tvOS 11.2+ as, despite the constant being marked as available earlier, it's not supported at runtime. (#33)
  • Convert JSONObject.ns and JSONObject.nsNoNull to return a [String: Any] instead of an [AnyHashable: Any]. (#25)
  • Split JSON.Encoder.encodeAs* and JSON.Decoder.decode methods into overload pairs where one takes options: and the other doesn't. This makes it easier to replace function references to JSONEncoder/JSONDecoder methods with the equivalents from PMJSON.
  • Add conformance to Combine's TopLevelEncoder and TopLevelDecoder, using Data as the input/output type. This means that JSON.Encoder.encode(_:) is now marked as deprecated instead of unavailable.
  • Rename JSON.flatMap* and JSONObject.flatMap* methods to .compactMap* instead when the transformation returns an optional. (#28)
  • Mark a lot of methods as @inlinable.

v3.1.2 (2018-11-06)

  • Add method JSONError.withPrefix(_:) that returns a new error by prepending a prefix onto the path. This can be used in custom parsing code to produce good errors if the existing convenience functions don't do what you want. (#26)

v3.1.1 (2018-05-17)

  • Squelch Swift 4.1 warnings.

v3.1.0 (2018-02-25)

  • Improve .pretty output for empty arrays/dictionaries.
  • Speed up JSON.encodeAsData() pretty significantly. It's now very nearly as fast as JSON.encodeAsString().
  • Speed up JSON.Encoder.encodeAsString() and JSON.Encoder.encodeAsData().
  • Add a couple of convenience static methods to JSON that mimic the enum cases: JSON.int(_:) and JSON.cgFloat(_:). These can be used when JSON(_:) triggers too much type complexity. Also add a JSON(_:) override for CGFloat.
  • Add JSON.Encoder.keyEncodingStrategy. This is very similar to Swift 4.1's JSONEncoder.keyEncodingStrategy, although by default it won't apply to any nested values of type JSON or JSONObject (there's another option applyKeyEncodingStrategyToJSONObject that controls this).
  • Add JSON.Decoder.keyDecodingStrategy. This is very similar to Swift 4.1's JSONDecoder.keyDecodingStrategy, although by default it won't apply to decoding any values of type JSON or JSONObject (there's another option applyKeyDecodingStrategyToJSONObject that controls this).
  • Add JSON.Encoder.dateEncodingStrategy. This is very similar to JSONEncoder.dateEncodingStrategy except it includes another case for encoding ISO8601-formatted dates with fractional seconds (on Apple platforms).
  • Add JSON.Decoder.dateDecodingStrategy. This is very similar to JSONDecoder.dateDecodingStrategy except it includes another case for decoding ISO8601-formatted dates with fractional seconds (on Apple platforms).
  • Add JSON.Encoder.dataEncodingStrategy. This is identical to JSONEncoder.dataEncodingStrategy.
  • Add JSON.Decoder.dataDecodingStrategy. This is identical to JSONDecoder.dataDecodingStrategy.

v3.0.2 (2018-02-21)

  • Add convenience property JSONError.path.
  • Add method JSONError.withPrefixedCodingPath(_:) to make it easier to use JSONError-throwing methods in a Decodable implementation.

v3.0.1 (2018-02-18)

  • Fix Swift Package Manager support.

v3.0.0 (2018-02-18)

  • Convert to Swift 4.
  • Implement Codable on JSON.
  • Add a Swift.Decoder implementation called JSON.Decoder.
  • Add a Swift.Encoder implementation called JSON.Encoder.

v2.0.3 (2017-09-12)

  • Add Linux support for Decimal (on Swift 3.1 and later). NOTE: Decimal support is still buggy in Swift 3.1, and the workarounds we employ to get the correct values on Apple platforms don't work on Linux. You probably shouldn't rely on this working correctly on Linux until Swift fixes its Decimal implementation.
  • Add Linux support for decoding from/encoding to Data.
  • Add Linux support for LocalizedError on the Error types (only really applies to Swift 3.1 and later).
  • Fix compilation on Linux using the release configuration.
  • Support running the test suite with swift test.

v2.0.2 (2017-03-06)

  • Fix Linux compatibility.

v2.0.1 (2017-02-26)

  • Add method JSON.parser(for:options:) that returns a JSONParser> from a Data. Like JSON.decode(_:options:), this method automatically detects UTF-8, UTF-16, or UTF-32 input.
  • Fix compatibility with Swift Package Manager.

v2.0.0 (2017-01-02)

  • Add full support for decimal numbers (on supported platforms). This takes the form of a new JSON variant .decimal, any relevant accessors, and full parsing/decoding support with the new option .useDecimals. With this option, any number that would have been decoded as a Double will be decoded as a Decimal instead.
  • Add a set of forEach accessors for working with arrays, similar to the existing map and flatMap accessors.

v1.2.1 (2016-10-27)

  • Handle UTF-32 input.
  • Detect UTF-16 and UTF-32 input without a BOM.
  • Fix bug where we weren't passing decoder options through for UTF-16 input.

v1.2.0 (2016-10-27)

  • Change how options are provided to the encoder/decoder/parser. All options are now provided in the form of a struct that uses array literal syntax (similar to OptionSets). The old methods that take strict/pretty flags are now marked as deprecated.
  • Add a new depth limit option to the decoder, with a default of 10,000.
  • Implement a new test suite based on JSONTestSuite.
  • Fix a crash if the input stream contained a lone trail surrogate without a lead surrogate.
  • Fix incorrect parsing of numbers of the form 1e-1 or 1e+1.
  • When the strict option is specified, stop accepting numbers of the form 01 or -01.
  • Add support for UTF-16 when decoding a Data that has a UTF-16 BOM.
  • Skip a UTF-8 BOM if present when decoding a Data.

v1.1.0 (2016-10-20)

  • Add Hashable to JSONEvent and JSONParserError.
  • Make JSONParserError conform to CustomNSError for better Obj-C errors.
  • Full JSON stream support. JSONParser and JSONDecoder can now both operate in streaming mode, a new type JSONStreamDecoder was added as a lazy sequence of JSON values, and a convenience method JSON.decodeStream(_:) was added.
  • Rename JSONEventGenerator to JSONEventIterator and JSONParserGenerator to JSONParserIterator. The old names are available (but deprecated) for backwards compatibility.
  • Add support for pattern matching with JSONParserError. It should now work just like any other error, allowing you to say e.g. if case JSONParserError.invalidSyntax = error { … }.

v1.0.1 (2016-09-15)

  • Fix CocoaPods.

v1.0.0 (2016-09-08)

  • Support Swift 3.0.
  • Add setters for basic accessors so you can write code like json["foo"].object?["key"] = "bar".
  • Provide a localized description for errors when bridged to NSError.
  • Add support to JSONParser for streams of JSON values (e.g. "[1][2]").

v0.9.3 (2016-05-23)

  • Add a set of convenience methods on JSON and JSONObject for mapping arrays returned by subscripting with a key or index: mapArray(_:_:), mapArrayOrNil(_:_:), flatMapArray(_:_:), and flatMapArrayOrNil(_:_:).
  • Add new set of convenience JSON initializers.
  • Change description and debugDescription for JSON and JSONObject to be more useful. description is now the JSON-encoded string.
  • Implement CustomReflectable for JSON and JSONObject.

v0.9.2 (2016-03-04)

  • CocoaPods support.

v0.9.1 (2016-02-19)

  • Linux support.
  • Swift Package Manager support.
  • Rename instances of plist in the API to ns. The old names are still available but marked as deprecated.
  • Support the latest Swift snapshot (2012-02-08).

v0.9 (2016-02-12)

Initial release.

Comments
  • try PMJSON.JSON.decode leaks

    try PMJSON.JSON.decode leaks

    Hello, I found many memory leaks if I use try PMJSON.JSON.decode(jsonData) scalars.append(c) caused issue in function: private mutating func parseValue(_ c: UnicodeScalar) throws -> JSONEvent

    opened by iDevPro 8
  • Security review notes for followup

    Security review notes for followup

    I did a quick security-focused review and these are my notes. PTAL and assess if there's anything that makes sense to follow up on.


    “A convenience method is also provided for decoding from a Data containing data encoded as UTF-8, UTF-16, or UTF-32”

    • Is this done via the BOM or sniffing?
    • What happens if malicious data within JSON includes a BOM in order to trick the parser into parsing data as JSON that should just be considered to be data?
    • Or if the encoding of the JSON is determined via sniffing logic, maybe data can influence this sniffing to achieve the same effect as described above.
    • How is malformed UTF-8 handled? Is there normalization? E.g.: Could a double-width quote in data be normalized back to a quote somewhere, enabling data that’s supposed to be encoded within JSON to actually affect the JSON structure as understood by the parser?
    • Usage of various things marked “unsafe”... Not immediately sure if these are being used in a safe manner: https://github.com/postmates/PMJSON/search?q=unsafe&unscoped_q=unsafe ...or the extent to which this matters, given the properties of swift w.r.t. memory safety.

    Sorry for not being more specific on a lot of this -- I'm new to swift. I think it all of this may just translate to having appropriate test cases, such as using the BOM inside JSON data being decoded, etc. as per above.

    opened by randomdross 4
  • Quick fix for PMJSON on Linux

    Quick fix for PMJSON on Linux

    I've integrated PMJSON to parse big JSON file on a Kitura project and recognised that PMJSON 2.0.1 wouldn't compile on the ibmcom/swift-ubuntu docker image (for example). On Linux, the DecimalPaceholder object couldn't be compared (thus the == function), a few methods couldn't be called because there are changes to swift that prevent fileprivate or private methods to be called. Lastly I had to add some ! for the strtod call. It works for me now, maybe you could review the changes or test in your own branch. Thanks for your great work!


    This change is Reviewable

    opened by VolkerBb 4
  • Disables tests in the PM due to layout problems

    Disables tests in the PM due to layout problems

    Hi!

    I love using PMJSON, but I had to fork it to use it with the Swift package manager. The problem is that the structure of the Tests directory is non-compliant with the PM. Would you be interested in addressing it?

    Thanks!


    This change is Reviewable

    opened by hpux735 4
  • Add CocoaPods support

    Add CocoaPods support

    Hey, this pull request would close #2

    • [x] create podspec
    • [x] podspec passes lint
    dkhamsing$ pod --version
    0.39.0
    
    dkhamsing$ pod spec lint PMJSON.podspec 
    
     -> PMJSON (0.9)
    
    Analyzed 1 podspec.
    
    PMJSON.podspec passed validation.
    
    • [x] simple test demo project https://github.com/dkhamsing/PMJSON/tree/cocoapods-demo/CocoaPodsDemo
    import PMJSON
    
    let jsonString = "{\"id\":88}"
    print(jsonString)
    do {
        let json = try JSON.decode(jsonString)
        print (json)
    } catch _ {
        print ("sad")
    }             
    
    {"id":88}
    ["id": JSON.Int64(88)]
    
    • [x] get setup with CocoaPods Trunk service (to publish/make it public) @kballard https://guides.cocoapods.org/making/getting-setup-with-trunk.html
    • [x] update readme with text below @kballard

    To install using CocoaPods, add the following to your Podfile:

    pod 'PMJSON', '~> 0.9'
    
    opened by dkhamsing 2
  • Write streaming encoder

    Write streaming encoder

    Our decoder is structured such that we have a parser that produces a sequence of JSONEvents and a decoder that consumes this to actually decode into JSON. We should do the same for the encoder, where we have an encoder that produces a sequence of JSONEvents and an event-encoder that assembles it into the actual JSON output.

    Besides performance concerns, the downside to this approach is the JSONEvent sequence must be valid or else the event-encoder will produce invalid JSON output.

    opened by lilyball 1
  • Make a new release for Swift Package Manager support

    Make a new release for Swift Package Manager support

    0399644 fixed a bug that broke SwiftPM support. However, the current release (2.0.0) doesn't include this fix, therefore it is not possible to add PMJSON as a dependency of a SwiftPM project.

    Could you add a tag (e.g. 2.1.0 ) to the repo please? :) Thank you!

    opened by loiclec 1
  • Where you say

    Where you say "plist" you mean "Foundation"

    The PList set of Foundation types is not identical to the JSON set of Foundation types. They have most types in common, but also some differences. The former includes NSData and NSDate, the latter NSNull, which in turn the other does not contain.

    So where you say "plist" in the documentation and in code, you really mean the JSON set of Foundation types.

    opened by akempgen 1
  • SwiftDecoder.DateDecodingStrategy.iso8601WithFractionalSeconds should be marked as iOS 11.2+

    SwiftDecoder.DateDecodingStrategy.iso8601WithFractionalSeconds should be marked as iOS 11.2+

    It turns out that the relevant ISO8601DateFormatter.Options constant doesn't actually work until iOS 11.2, and crashes when used on iOS 11.0 or 11.1.

    I'm not sure if the other platforms have a similar problem.

    opened by lilyball 0
  • JSONError should have structured way to add prefixes

    JSONError should have structured way to add prefixes

    There are existing methods for doing parsing of objects and arrays that build up a full path on error. But if the user isn't using these particular methods, we lose that path. We should probably expose a way for the user to provide the path themselves. We'll probably want a more structured mechanism than the existing private withPrefix(_: String) method (e.g. perhaps we take an enum that has cases for object key vs array index).

    opened by lilyball 0
  • Allow for overriding Content-Type on HTTPManagerUploadJSONRequest

    Allow for overriding Content-Type on HTTPManagerUploadJSONRequest

    HTTPManagerUploadJSONRequest currently hardcodes the Content-Type as application/json. This is usually the right call, but we really should have a way to override this, such as by making the property mutable (as HTTPManagerUploadDataRequest does).

    enhancement 
    opened by lilyball 0
  • Convenience methods for processing an entire object

    Convenience methods for processing an entire object

    We have methods for mapping over arrays in a manner that produces good error messages, but we don't have any way to process all key/value pairs of an object in a way that produces good error messages. We should support both a forEach, a way to map the pairs into an array, and a way to map them into a Dictionary.

    opened by lilyball 0
  • Consider adding JSONCompatible protocol

    Consider adding JSONCompatible protocol

    We should consider having a JSONCompatible protocol that is conformed to by things like String, Int, etc, as a replacement for the family of JSON.init(_:) initializers. We could then have a single JSON.init(_:) initializer that is generic using this protocol.

    The goal here is to sidestep the type-checking complexity issue when using a bunch of JSON(foo) calls in the same expression.

    We should also do some microbenchmarks on performance, because generics are implemented using a dictionary-passing mechanism, and we want to make sure that switching to a single generic initializer doesn't have a significant effect on how long it takes to construct these.

    Note that if we do this we might have to bump the major version in order to mark the existing JSON.init(_:) methods as unavailable. The problem is that just leaving them as deprecated is still likely going to incur the type-checking penalty. But we should test.

    opened by lilyball 2
  • Automatically use Decimal for large numbers

    Automatically use Decimal for large numbers

    We should detect when a number can't be represented exactly by an Int64 or a Double and fall back to Decimal. We can then expose an option that turns off this behavior.

    opened by lilyball 0
  • Make decoder non-recursive

    Make decoder non-recursive

    A recursive decoder means we can't decode arbitrarily-deep JSON hierarchies. If we switch to storing our decoding state in an array instead of on the stack, we can remove this limitation.

    Note: Test performance to make sure that using an array doesn't noticeably slow down the decoder.

    opened by lilyball 1
Releases(v4.0.0)
  • v4.0.0(Nov 15, 2019)

    • Update to Swift 5.
    • When encoding/decoding URLs with JSON.Encoder and JSON.Decoder, encode and decode their absolute string instead of relying on the native implementation which encodes them as an object. This matches the behavior of JSONEncoder and JSONDecoder.
    • Fix availability attribute for JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds.
    • Bump JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds and JSON.Encoder.DateEncodingStrategy.iso8601WithFractionalSeconds to iOS 11.2+ and tvOS 11.2+ as, despite the constant being marked as available earlier, it's not supported at runtime. (#33)
    • Convert JSONObject.ns and JSONObject.nsNoNull to return a [String: Any] instead of an [AnyHashable: Any]. (#25)
    • Split JSON.Encoder.encodeAs* and JSON.Decoder.decode methods into overload pairs where one takes options: and the other doesn't. This makes it easier to replace function references to JSONEncoder/JSONDecoder methods with the equivalents from PMJSON.
    • Add conformance to Combine's TopLevelEncoder and TopLevelDecoder, using Data as the input/output type. This means that JSON.Encoder.encode(_:) is now marked as deprecated instead of unavailable.
    • Rename JSON.flatMap* and JSONObject.flatMap* methods to .compactMap* instead when the transformation returns an optional. (#28)
    • Mark a lot of methods as @inlinable.
    Source code(tar.gz)
    Source code(zip)
  • v3.1.2(Nov 7, 2018)

    • Add method JSONError.withPrefix(_:) that returns a new error by prepending a prefix onto the path. This can be used in custom parsing code to produce good errors if the existing convenience functions don't do what you want. (#26)
    Source code(tar.gz)
    Source code(zip)
  • v3.1.1(May 18, 2018)

  • v3.1.0(Feb 26, 2018)

    • Improve .pretty output for empty arrays/dictionaries.
    • Speed up JSON.encodeAsData() pretty significantly. It's now very nearly as fast as JSON.encodeAsString().
    • Speed up JSON.Encoder.encodeAsString() and JSON.Encoder.encodeAsData().
    • Add a couple of convenience static methods to JSON that mimic the enum cases: JSON.int(_:) and JSON.cgFloat(_:). These can be used when JSON(_:) triggers too much type complexity. Also add a JSON(_:) override for CGFloat.
    • Add JSON.Encoder.keyEncodingStrategy. This is very similar to Swift 4.1's JSONEncoder.keyEncodingStrategy, although by default it won't apply to any nested values of type JSON or JSONObject (there's another option applyKeyEncodingStrategyToJSONObject that controls this).
    • Add JSON.Decoder.keyDecodingStrategy. This is very similar to Swift 4.1's JSONDecoder.keyDecodingStrategy, although by default it won't apply to decoding any values of type JSON or JSONObject (there's another option applyKeyDecodingStrategyToJSONObject that controls this).
    • Add JSON.Encoder.dateEncodingStrategy. This is very similar to JSONEncoder.dateEncodingStrategy except it includes another case for encoding ISO8601-formatted dates with fractional seconds (on Apple platforms).
    • Add JSON.Decoder.dateDecodingStrategy. This is very similar to JSONDecoder.dateDecodingStrategy except it includes another case for decoding ISO8601-formatted dates with fractional seconds (on Apple platforms).
    • Add JSON.Encoder.dataEncodingStrategy. This is identical to JSONEncoder.dataEncodingStrategy.
    • Add JSON.Decoder.dataDecodingStrategy. This is identical to JSONDecoder.dataDecodingStrategy.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.2(Feb 22, 2018)

    • Add convenience property JSONError.path.
    • Add method JSONError.withPrefixedCodingPath(_:) to make it easier to use JSONError-throwing methods in a Decodable implementation.
    Source code(tar.gz)
    Source code(zip)
  • v3.0.1(Feb 19, 2018)

  • v3.0.0(Feb 19, 2018)

    • Convert to Swift 4.
    • Implement Codable on JSON.
    • Add a Swift.Decoder implementation called JSON.Decoder.
    • Add a Swift.Encoder implementation called JSON.Encoder.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.3(Sep 12, 2017)

    • Add Linux support for Decimal (on Swift 3.1 and later). NOTE: Decimal support is still buggy in Swift 3.1, and the workarounds we employ to get the correct values on Apple platforms don't work on Linux. You probably shouldn't rely on this working correctly on Linux until Swift fixes its Decimal implementation.
    • Add Linux support for decoding from/encoding to Data.
    • Add Linux support for LocalizedError on the Error types (only really applies to Swift 3.1 and later).
    • Fix compilation on Linux using the release configuration.
    • Support running the test suite with swift test.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.2(Mar 6, 2017)

  • v2.0.1(Feb 26, 2017)

    • Add method JSON.parser(for:options:) that returns a JSONParser<AnySequence<UnicodeScalar>> from a Data. Like JSON.decode(_:options:), this method automatically detects UTF-8, UTF-16, or UTF-32 input.
    • Fix compatibility with Swift Package Manager.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Jan 3, 2017)

    • Add full support for decimal numbers (on supported platforms). This takes the form of a new JSON variant .decimal, any relevant accessors, and full parsing/decoding support with the new option .useDecimals. With this option, any number that would have been decoded as a Double will be decoded as a Decimal instead.
    • Add a set of forEach accessors for working with arrays, similar to the existing map and flatMap accessors.
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Oct 27, 2016)

    • Handle UTF-32 input.
    • Detect UTF-16 and UTF-32 input without a BOM.
    • Fix bug where we weren't passing decoder options through for UTF-16 input.
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Oct 27, 2016)

    • Change how options are provided to the encoder/decoder/parser. All options are now provided in the form of a struct that uses array literal syntax (similar to OptionSets). The old methods that take strict/pretty flags are now marked as deprecated.
    • Add a new depth limit option to the decoder, with a default of 10,000.
    • Implement a new test suite based on JSONTestSuite.
    • Fix a crash if the input stream contained a lone trail surrogate without a lead surrogate.
    • Fix incorrect parsing of numbers of the form 1e-1 or 1e+1.
    • When the strict option is specified, stop accepting numbers of the form 01 or -01.
    • Add support for UTF-16 when decoding a Data that has a UTF-16 BOM.
    • Skip a UTF-8 BOM if present when decoding a Data.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Oct 20, 2016)

    • Full JSON stream support. JSONParser and JSONDecoder can now both operate in streaming mode, a new type JSONStreamDecoder was added as a lazy sequence of JSON values, and a convenience method JSON.decodeStream(_:) was added.
    • Add support for pattern matching with JSONParserError. It should now work just like any other error, allowing you to say e.g. if case JSONParserError.invalidSyntax = error { … }.* Add Hashable to JSONEvent and JSONParserError.
    • Make JSONParserError conform to CustomNSError for better Obj-C errors.
    • Rename JSONEventGenerator to JSONEventIterator and JSONParserGenerator to JSONParserIterator. The old names are available (but deprecated) for backwards compatibility.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Sep 15, 2016)

  • v1.0.0(Sep 8, 2016)

  • v0.9.4(Sep 8, 2016)

    This release supports Swift 2.3, in addition to the following changes:

    • Add setters for basic accessors so you can write code like json["foo"].object?["key"] = "bar".
    • Add optional NSError userInfo provider for JSONError. Setting this up requires calling JSONError.registerNSErrorUserInfoProvider().
    Source code(tar.gz)
    Source code(zip)
  • v0.9.3(May 23, 2016)

    • Add new set of convenience JSON initializers.
    • Change description and debugDescription for JSON and JSONObject to be more useful. description is now the JSON-encoded string.
    • Implement CustomReflectable for JSON and JSONObject.
    Source code(tar.gz)
    Source code(zip)
  • v0.9.2(May 23, 2016)

  • v0.9.1(Feb 19, 2016)

    • Linux support.
    • Swift Package Manager support.
    • Rename instances of plist in the API to ns. The old names are still available but marked as deprecated.
    • Support the latest Swift snapshot (2012-02-08).
    Source code(tar.gz)
    Source code(zip)
  • v0.9(Feb 12, 2016)

Owner
Postmates Inc.
Postmates Inc.
The easy to use Swift JSON decoder

Unbox is deprecated in favor of Swift’s built-in Codable API and the Codextended project. All current users are highly encouraged to migrate to Codable as soon as possible.

John Sundell 2k Dec 31, 2022
A enhanced JSON decoder.

JSONDecoderEx A enhanced JSON decoder. Usage struct User: Codable { struct Role: OptionSet, Codable, CustomStringConvertible { let rawValu

SAGESSE-CN 105 Dec 19, 2022
A enhanced JSON decoder.

JSONDecoderEx A enhanced JSON decoder. Usage struct User: Codable { struct Role: OptionSet, Codable, CustomStringConvertible { let rawValu

SAGESSE-CN 105 Dec 19, 2022
SwiftyJSON decoder for Codable

SwiftyJSONDecoder 功能 继承自 JSONDecoder,在标准库源码基础上做了改动,与其主要区别如下 使用 SwiftyJSON 解析数据,使用其类型兼容功能 废弃 nonConformingFloatDecodingStrategy 属性设置,Double 及 Float 默认解

null 2 Aug 10, 2022
Dogtector: dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized

Dogtector Project description Dogtector is dog breed detection app for iOS using YOLOv5 model combined with Metal based object decoder optimized for u

Bartłomiej Pluta 21 Aug 1, 2022
JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.

JSEN /ˈdʒeɪsən/ JAY-sən JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift. A JSON, as defined in the EC

Roger Oba 8 Nov 22, 2022
Swift-json - High-performance json parsing in swift

json 0.1.4 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Jay - Pure-Swift JSON parser & formatter. Fully streamable input and output. Linux & OS X ready.

Pure-Swift JSON parser & formatter. Fully streamable input and output. Linux & OS X ready. Replacement for NSJSONSerialization.

Danielle 132 Dec 5, 2021
JSON-Practice - JSON Practice With Swift

JSON Practice Vista creada con: Programmatic + AutoLayout Breve explicación de l

Vanesa Giselle Korbenfeld 0 Oct 29, 2021
Ss-json - High-performance json parsing in swift

json 0.1.1 swift-json is a pure-Swift JSON parsing library designed for high-per

kelvin 43 Dec 15, 2022
Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON.

JSONFeed Swift parser for JSON Feed — a new format similar to RSS and Atom but in JSON. For more information about this new feed format visit: https:/

Toto Tvalavadze 31 Nov 22, 2021
Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs

Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs.

Julio Cesar Guzman Villanueva 2 Oct 6, 2022
Implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top of Swift's Codable implementations.

DynamicCodableKit DynamicCodableKit helps you to implement dynamic JSON decoding within the constraints of Swift's sound type system by working on top

SwiftyLab 15 Oct 16, 2022
SwiftIB is a pure Swift implementation of the Interactive Brokers TWS API library on Mac OS X

SwiftIB is a pure Swift implementation of the Interactive Brokers TWS API library on Mac OS X, with Core Foundation of crouse. All the API interfaces are implemented. Request Market Data and Request History Data interface are thoroughly tested.

Harry Li 24 Sep 14, 2022
AlamofireObjectMappe - An Alamofire extension which converts JSON response data into swift objects using ObjectMapper

AlamofireObjectMapper An extension to Alamofire which automatically converts JSON response data into swift objects using ObjectMapper. Usage Given a U

Tristan Himmelman 2.6k Dec 29, 2022
Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable

Elevate is a JSON parsing framework that leverages Swift to make parsing simple, reliable and composable. Elevate should no longer be used for

Nike Inc. 611 Oct 23, 2022
Freddy - A reusable framework for parsing JSON in Swift.

Why Freddy? Parsing JSON elegantly and safely can be hard, but Freddy is here to help. Freddy is a reusable framework for parsing JSON in Swift. It ha

Big Nerd Ranch 1.1k Jan 1, 2023
[Deprecated] A shiny JSON parsing library in Swift :sparkles: Loved by many from 2015-2021

?? Deprecation Notice ?? Gloss has been deprecated in favor of Swift's Codable framework. The existing Gloss source is not going away, however updates

Harlan Kellaway 1.6k Nov 24, 2022
HandyJSON is a framework written in Swift which to make converting model objects to and from JSON easy on iOS.

HandyJSON To deal with crash on iOS 14 beta4 please try version 5.0.3-beta HandyJSON is a framework written in Swift which to make converting model ob

Alibaba 4.1k Dec 29, 2022