Upgrade to Pro — share decks privately, control downloads, hide ads and more …

XMLのObject Mapping

XMLのObject Mapping

XMLとかのObjectMapperを作るときの、3つのアプローチについて

8766b19fe1c1f8475e233c910ed6440f?s=128

kobito-kaba

June 21, 2018
Tweet

More Decks by kobito-kaba

Other Decks in Programming

Transcript

  1. XMLのObject Mapping Yahoo! JAPAN 森洋之

  2. 森 洋之 @moridroid

  3. 森 洋之 @moridroid Yahoo! JAPAN Androidアプリ黒帯  (こういうところで話す仕事)

  4. 森 洋之 @moridroid Yahoo! JAPAN Androidアプリ黒帯  (こういうところで話す仕事) ヤフオク!のアプリ担当

  5. goo.gl/fW2YPh

  6. None
  7. はじめます

  8. Codable

  9. { "name": "hoge", "sex": 0, "birthday": "19900530", "mail_address": "hoge@gmail.com" }

    struct User: Codable { let name: String let sex: Int let birthday: String let mail_address: String } JSON struct
  10. None
  11. None
  12. Gson

  13. Gson Jackson

  14. Gson Jackson Moshi

  15. Gson Jackson Moshi SimpleXML

  16. Gson Jackson Moshi SimpleXML JAXB

  17. 基本的なロジック

  18. <User> <name>Taro</name> <age>18</age> <locale>Japan</locale> </User>

  19. User - name uninitialized - age uninitialized - locale uninitialized

    <User> <name>Taro</name> <age>18</age> <locale>Japan</locale> </User> val user = User( )
  20. User - name ”Taro” - age uninitialized - locale uninitialized

    <User> <name>Taro</name> <age>18</age> <locale>Japan</locale> </User> user.name = “Taro”
  21. User - name ”Taro” - age 18 - locale uninitialized

    <User> <name>Taro</name> <age>18</age> <locale>Japan</locale> </User> user.age = 18
  22. User - name ”Taro” - age 18 - locale ”Japan”

    <User> <name>Taro</name> <age>18</age> <locale>Japan</locale> </User> user.locale = “Japan”
  23. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized
  24. None
  25. data class Excellent!!

  26. data class User(val name : String, val age : Int,

    val locale : String)
  27. data class User(val name : String, val age : Int,

    val locale : String) コンストラクタ
  28. data class User(val name : String, val age : Int,

    val locale : String) コンストラクタ イミュータブル
  29. data class User(val name : String, val age : Int,

    val locale : String) コンストラクタ イミュータブル 非null
  30. 基本的なロジック again!!

  31. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized
  32. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized 空のコンストラクタ無い
  33. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized イミュータブル 空のコンストラクタ無い
  34. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized イミュータブル 空のコンストラクタ無い 非null
  35. User - name ”Taro” - age 18 - locale ”Japan”

    User - name uninitialized - age uninitialized - locale uninitialized イミュータブル 空のコンストラクタ無い 非null 考え方が合わない
  36. 無理に使うなら

  37. data class User(var name : String?, var age : Int?,

    var locale : String?)
  38. data class User(var name : String?, var age : Int?,

    var locale : String?) ミュータブル
  39. data class User(var name : String?, var age : Int?,

    var locale : String?) ミュータブル nullable
  40. data class User(var name : String?, var age : Int?,

    var locale : String?) ミュータブル nullable 糞プロパティ 爆誕
  41. じゃあどうするか

  42. JSON

  43. JSON Moshi

  44. XML

  45. XML  見なかった  ことにする

  46. None
  47. XML  自分で作る

  48. 3つのアプローチ

  49. 1. Reflection

  50. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox>
  51. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> data class Inbox( val name : String, val mails : List<Mail>) data class Mail( val title : String, val body : String, val from : User) data class User( val name : String, val address : String)
  52. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> data class Inbox( val name : String, val mails : List<Mail>) data class Mail( val title : String, val body : String, val from : User) data class User( val name : String, val address : String) inline fun <reified T> fromXML(xml : InputStream) : T? { // ... }
  53. inline fun <reified T> fromXML(xml : InputStream) : T? {

    // ... } val inbox = fromXML<Inbox>(inpustStream)
  54. Mail - title : String - body : String -

    from : User User - name : String - address : String Inbox - name : String - mail : List<Mail>
  55. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値
  56. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name - Mails
  57. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails
  58. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails [ ]
  59. index オブジェクト プロパティ 値 1 Inbox - name 受信箱 -

    Mails [2] 2 Mail - title - body - User <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User> </Mail> … </Mails> </Inbox>
  60. index オブジェクト プロパティ 値 1 Inbox - name 受信箱 -

    Mails [2] 2 Mail - title - body - User <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User> </Mail> … </Mails> </Inbox>
  61. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails [2] 2 Mail - title 主人がオオアリクイに … - body いきなりのメール失礼 … - User 3 3 User - name - address
  62. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails [2] 2 Mail - title 主人がオオアリクイに … - body いきなりのメール失礼 … - User 3 3 User - name - address
  63. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails [2] 2 Mail - title 主人がオオアリクイに … - body いきなりのメール失礼 … - User 3 3 User - name オオアリクイ - address spam@example.com
  64. <Inbox> <name>受信箱</name> <Mails> <Mail> <title>主人がオオアリクイに…</title> <body>いきなりのメール失礼…</body> <User> <name>オオアリクイ</name> <address>spam@example.com</address> </User>

    </Mail> … </Mails> </Inbox> index オブジェクト プロパティ 値 1 Inbox - name 受信箱 - Mails [2, 4, 6, ...] 2 Mail - title 主人がオオアリクイに … - body いきなりのメール失礼 … - User 3 3 User - name オオアリクイ - address spam@example.com 4 Mail - title 私はチンパンジーです。 - body はじめまして。早苗と …
  65. Mail - title : String - body : String -

    from : User User - name : String - address : String Inbox - name : String - mail : List<Mail>
  66. Reflection

  67. Reflection Pros 作るのが楽

  68. Reflection Pros 作るのが楽 Cons Reflectionであること

  69. Reflection Pros 作るのが楽 Cons Reflectionであること      ・遅い      ・kotlin-reflect、でかい

  70. 2. APT

  71. None
  72. クラス追加

  73. interface XMLAdapter<T> { fun fromXml(xml : InputStream) : T? }

  74. inline fun <reified T> xmlAdapter( ) : XMLAdapter<T?> { //

    ... } interface XMLAdapter<T> { fun fromXml() : T? }
  75. data class Inbox( val name : String, val mails :

    List<Mail>) data class Mail( val title : String, val body : String, val from : User) data class User( val name : String, val address : String)
  76. @XmlClass data class Inbox( val name : String, val mails

    : List<Mail>) @XmlClass data class Mail( val title : String, val body : String, val from : User) @XmlClass data class User( val name : String, val address : String)
  77. @XmlClass data class Inbox( val name : String, val mails

    : List<Mail>) @XmlClass data class Mail( val title : String, val body : String, val from : User) @XmlClass data class User( val name : String, val address : String) class Inbox_XmlAdapter : XmlAdapter<Inbox> class Mail_XmlAdapter : XmlAdapter<Mail> class User_XmlAdapter : XmlAdapter<User>
  78. inline fun <reified T> xmlAdapter( ) : XMLAdapter<T?> { return

    Class.forName(“${T::class.name}_XmlAdapter”).newInstance() }
  79. val adapter = xmlAdapter<Inbox>() val inbox = adapter.fromXml(inputStream) inline fun

    <reified T> xmlAdapter( ) : XMLAdapter<T?> { return Class.forName(“${T::class.name}_XmlAdapter”).newInstance() }
  80. APT

  81. APT Pros Reflectionじゃないこと      拡張性高め

  82. APT Pros Reflectionじゃないこと      拡張性高め Cons めんどくさい      難読化したらまずい

  83. 3. Transform API

  84. None
  85. バイトコード変換

  86. goo.gl/u5XHJi

  87. inline fun <reified T> xmlAdapter( ) : XMLAdapter<T?> { return

    when(T::class) { Inbox::class -> Inbox_XmlAdapter() Mail::class -> Mail_XmlAdapter() ... } }
  88. Transform API

  89. Transform API Pros 難読化しても影響ない

  90. Transform API Pros 難読化しても影響ない Cons 超めんどくさい      バイトコードだから…

  91. まとめ

  92. つくろうぜ! オブジェクトマッパー

  93. None
  94. おしまい