Objectmapper: How to put conditions in Mapping method ?

Created on 5 Oct 2016  ·  4Comments  ·  Source: tristanhimmelman/ObjectMapper

I try to implement a StreetAddress struct from Google Map place API but dunno how it's possible to be flexible in mapping method, I didn't see anything related to this in current documentation.

For example in my struct, I have a street number and route property.
Here is a sample of JSON response from google API:

"address_components": [
{
"long_name": "36",
"short_name": "36",
"types": [
"street_number"
]
},
{
"long_name": "Rue de Dunkerque",
"short_name": "Rue de Dunkerque",
"types": [
"route"
]
},

I didn't see a way to have guard conditions, something like this:

guard let components = map["result.address_components"] as? [[String:Any]] else {
return
}
// other...

Then I could find a way to retrieve manually these informations but of course, this beginning of sample code doesn't work.

Is a Transform needed for this or there is another way ?

Most helpful comment

Ok that's what I thought, thanks for this clean solution man, very useful !

All 4 comments

I'm not sure what you intend to do. If you'd like to...

  1. Make initializer fail when there's no result.address_components in the JSON.

=> See https://github.com/Hearst-DD/ObjectMapper#init_-map-map

  1. Use default value instead when there's no result.address_components in the JSON.

=> You might need to use Transform. See my answer in similar question: #606

No in fact result.address_components contains an array where I want to retrieve different values. Sorry the JSON sample is badly formatted in my first post.

I have these two properties client-side:

var route: String?
var streetNumber: String?

These two values are presents in address_components array, and depend on the property "type" in each objects of this array. So I'd need conditions to map them to corresponding properties

route should be mapped with value: Rue de Dunkerque & streetNumber should equal to 36

Oh, I got it. In this case you should use your own Transform. I would do like this:

struct AddressComponent {
  var route: String?
  var streetNumber: String?
}

let addressComponentRouteTransform = TransformOf<[[String: Any]], AddressComponent>(
  // Input:
  //     [
  //       {
  //         "long_name": "36",
  //         "short_name": "36",
  //         "types": [
  //           "street_number"
  //         ]
  //       },
  //       {
  //         "long_name": "Rue de Dunkerque",
  //         "short_name": "Rue de Dunkerque",
  //         "types": [
  //           "route"
  //         ]
  //       }
  //     ]
  //
  // Output:
  //     AddressComponent(route: "36", streetName: "Rue de Dunkerque")
  fromJSON: { (componentDicts: [[String: Any]]?) -> AddressComponent?
    let route = componentDicts?.lazy
      .filter {
        guard let types = $0["types"] as? [String] else { return false }
        return types.contains("route")
      }
      .flatMap {
        $0["long_name"] as? String
      }
    let streetNumber = componentDicts?.lazy
      .filter {
        guard let types = $0["types"] as? [String] else { return false }
        return types.contains("street_number")
      }
      .flatMap {
        $0["long_name"] as? String
      }
  },

  // Input:
  //     AddressComponent(route: "36", streetName: "Rue de Dunkerque")
  //
  // Output:
  //     [
  //       {
  //         "long_name": "36",
  //         "short_name": "36",
  //         "types": [
  //           "street_number"
  //         ]
  //       },
  //       {
  //         "long_name": "Rue de Dunkerque",
  //         "short_name": "Rue de Dunkerque",
  //         "types": [
  //           "route"
  //         ]
  //       }
  //     ]
  toJSON: { (component: AddressComponent?) -> [[String: Any]]?
    var componentDicts: [[String: Any]] = []
    if let route = component?.route {
      componentDicts.append([
        "long_name": route,
        "short_name": route,
        "types": [
          "route",
        ],
      ])
    }
    if let streetNumber = component?.streetNumber {
      componentDicts.append([
        "long_name": streetNumber,
        "short_name": streetNumber,
        "types": [
          "street_number",
        ],
      ])
    }
    return componentDicts
  }
)

struct Venue {
  var address: AddressComponent

  mutating func mapping(map: Map) {
    self.address <- (map["address_components"], addressComponentRouteTransform)
  }
}
Tip: Use 3 backticks(`) to make a code block in markdown.

func doSomething() {
}
func doSomething() {
}
Or you can use `
` tag if you want to make a bold text somewhere.

<pre>
func <strong>doSomething</strong>() {
}
</pre>
func doSomething() {
}

Ok that's what I thought, thanks for this clean solution man, very useful !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Dbigshooter picture Dbigshooter  ·  4Comments

liltimtim picture liltimtim  ·  3Comments

delbyze picture delbyze  ·  3Comments

borut-t picture borut-t  ·  4Comments

pcompassion picture pcompassion  ·  3Comments