Skip to content

4.Sourcery AutoJSONDeserializable

Olivier Halligon edited this page Sep 20, 2017 · 3 revisions

Classroom Walkthrough (Part 4)

JSON Parsing

We'll now use another template to make Sourcery generate the code for JSON parsing

Step 4.1

public protocol JSONDeserializable {
    init?(JSONObject: Any)
}

(💡 We could also of course instead create a separate file to put that protocol declaration into for clarity)

See how the template will only consider types annotated with the AutoJSONDeserializable Sourcery annotation.

Sourcery is able to detect special comments in the form of // sourcery: AnyThing so that you can annotate your code (akin to how SwiftLint does).

So here instead of using a phantom protocol like with AutoCases, this template expect to use annotations to opt-in for JSON code generation.

Step 4.2

  • Search for // FIXME: sourcery: AutoJSONDeserializable in the source code
  • Remove the FIXME: text to only keep the // sourcery: AutoJSONDeserializable comment/annotation on the line just above each model struct declaration:
// sourcery: AutoJSONDeserializable
struct Address {
  

Step 4.3

  • Start a Build to make Sourcery generate the code for that new template we added
  • Add the AutoJSONDeserializable.generated.swift file to your CodeGenDemo/CodeGen/Generated group in your Xcode project
  • Build again. 🛑 You'll notice a compiler error when trying to import Sourcery_AutoJSONSerializable in AutoJSONDeserializable.generated.swift
  • Look at the AutoJSONDeserializable.stencil template and notice the top of the code inserting that line. From there you have two solutions:
    1. Remove lines 4-6 of the stencil template to never do that import
    2. Or understand the logic of that template which only do that import if argument.removePodImport is not set.

Sourcery allows you to specify custom arguments to pass to templates, so we can do that by editing the .sourcery.yml file to add that argument:

# .sourcery.yml
sources:
  - CodeGenDemo
templates:
  - CodeGenDemo/CodeGen/Templates
output: CodeGenDemo/CodeGen/Generated
args:
  removePodImport: true
  • Start another Build. The import has disappeared from the generated code and the code should now compile 🎉

Step 4.4

  • Edit the PersonListViewController.swift to replace lines 21-38 (from // FIXME: Sourcery AutoJSONDeserializable to dataSource = [p1, p2].map { Ref(object: $0) } with code parsing the data.json file (already embedded in the project):
  override func viewDidLoad() {
    super.viewDidLoad()

    do {
      let data = try Data(contentsOf: Bundle.main.url(forResource: "data", withExtension: "json")!)
      let json = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
      dataSource = json.map({ personJSON in
        let p = Person(JSONObject: personJSON)!
        return Ref(object: p)
      })
    } catch let e {
      print("Error: ", e)
    }

    let dupes = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(findDupes))
    self.navigationItem.rightBarButtonItem = dupes
  }

😱 I discourage the use of force-unwrap in your code (like as! or !) in general, but for the purpose of this classroom as we want to focus on Code Generation, we'll let it slip 😉 Be sure to do proper error handling in your real code instead.

➡️ Next Steps

Clone this wiki locally