{"action":"opened","issue":{"url":"https://api.github.com/repos/chrsmith/google-api-java-client/issues/73","labels_url":"https://api.github.com/repos/chrsmith/google-api-java-client/issues/73/labels{/name}","comments_url":"https://api.github.com/repos/chrsmith/google-api-java-client/issues/73/comments","events_url":"https://api.github.com/repos/chrsmith/google-api-java-client/issues/73/events","html_url":"https://github.com/chrsmith/google-api-java-client/issues/73","id":59522166,"number":73,"title":"Xml parser should support parsing derived classes","user":{"login":"GoogleCodeExporter","id":9614759,"avatar_url":"https://avatars.githubusercontent.com/u/9614759?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCodeExporter","html_url":"https://github.com/GoogleCodeExporter","followers_url":"https://api.github.com/users/GoogleCodeExporter/followers","following_url":"https://api.github.com/users/GoogleCodeExporter/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCodeExporter/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCodeExporter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCodeExporter/subscriptions","organizations_url":"https://api.github.com/users/GoogleCodeExporter/orgs","repos_url":"https://api.github.com/users/GoogleCodeExporter/repos","events_url":"https://api.github.com/users/GoogleCodeExporter/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCodeExporter/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/chrsmith/google-api-java-client/labels/auto-migrated","name":"auto-migrated","color":"ededed"},{"url":"https://api.github.com/repos/chrsmith/google-api-java-client/labels/Component-XML","name":"Component-XML","color":"ededed"},{"url":"https://api.github.com/repos/chrsmith/google-api-java-client/labels/Priority-Medium","name":"Priority-Medium","color":"ededed"},{"url":"https://api.github.com/repos/chrsmith/google-api-java-client/labels/Type-Enhancement","name":"Type-Enhancement","color":"ededed"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-03-02T18:24:21Z","updated_at":"2015-03-02T18:24:21Z","closed_at":null,"body":"```\n\nExternal references, such as a standards document, or specification?\n\n\nJava environments (e.g. Java 6, Android 2.2, App Engine 1.3.7, or All)?\n\n\nPlease describe the feature requested.\n\nProblem\n=======\n\nWhen Xml.java parses an xml response, it should support deserializing classes \nwhen inheritance is involved.\n\nE.g. consider the following example response (simplified for brevity).\n\n<Response>\n  <Entries>\n    <Entry type='UserById'>\n      <Id>xxxx</Id>\n      <Name>xxxx</Name>\n    </Entry>\n    <Entry type='UserByEmail'>\n      <EmailAddress>xxxx</EmailAddress>\n      <Name>xxxx</Name>\n    </Entry>\n    <Entry type='UserByDomain'>\n      <Domain>xxxx</Domain>\n      <Name>xxxx</Name>\n    </Entry>\n  </Entries>\n</Response>\n\nNow, my java classes could look like follows:\n\npublic class UserBase {\n  @Key(\"Name\")\n  public string name;\n} \n\nclass UserById extends UserBase {\n  @Key(\"Id\")\n  public string id;\n}\n\nclass UserByEmail extends UserBase {\n  @Key(\"EmailAddress\")\n  public string email;\n}\n\nclass UserByDomain extends UserBase {\n  @Key(\"Domain\")\n  public string domain;\n}\n\npublic class UserBaseList {\n  @Key(\"Entry\")\n  public List<UserBase> entries;\n}\n\npublic class Response {\n  @Key(\"Entries\")\n  public UserBaseList list;\n}\n\nHowever, the current Xml parser provides no way of actually parsing objects \ninto this format, since it has no way of knowing the actual types of UserBase \nfrom the xml at parse time.\n\nThe only way to make things work right now is to define the class as\n\npublic class UserBase {\n  @Key(\"Name\")\n  public string name;\n\n  @Key(\"Id\")\n  public string id;\n\n  @Key(\"EmailAddress\")\n  public string email;\n\n  @Key(\"Domain\")\n  public string domain;\n}\n\nwhich works, but isn't quite elegant, especially when the class has several \nfields, or if the objects map to business entities known to the end user.\n\nSuggested workaround\n====================\n\n1. Have a TypeResolver annotation to help Xml.java parse the types properly.\n\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TypeResolver {\n  Class<?> value();\n}\n\n2. Define a FieldTypeResolver interface.\n\npublic interface FieldTypeResolver {\n  Class<?> resolve(XmlPullParser parser, XmlNamespaceDictionary namespace);\n}\n\n3. Annotate the field under question with this type.\n\npublic class UserBaseList {\n  @TypeResolver(UserBaseTypeResolver.class)\n  @Key(\"Entry\")\n  public List<UserBase> entries;\n}\n\n4. Implement a custom FieldTypeResolver for resolving UserBaseType.\n\npublic class UserBaseTypeResolver implements FieldTypeResolver {\n  public Class<?> resolve(XmlPullParser parser, XmlNamespaceDictionary namespace) {\n    String type = parser.getAttributeValue(\"\", \"type\");\n    if (type.compareTo(\"UserByEmail\") == 0) {\n      return UserByEmail.class;\n    } else if (type.compareTo(\"UserById\") == 0) {\n      return UserById.class;\n    } else if (type.compareTo(\"UserByDomain\") == 0) {\n      return UserByDomain.class;\n    } else {\n      return UserBase.class;\n    }\n  }\n}\n\n5. Modify Xml.java to query the field for a FieldTypeResolver while \ndeserializing the objects. (Simplified for brevity).\n\nClass<?> fieldClass = null;\n\nfield == null ? null : field.getType();\n\nFieldTypeResolver resolver = getFieldResolver(field);\n            \nif (resolver != null) {\n  fieldClass = resolver.resolve(parser, namespaceDictionary);\n} else {\n  fieldClass = field == null ? null : field.getType();\n}\n\nprivate static FieldTypeResolver getFieldResolver(Field field) {\n  TypeResolver resolver = field.getAnnotation(TypeResolver.class);\n  if (resolver == null) {\n    return null;\n  }\n  try {\n    return (FieldTypeResolver) resolver.value().newInstance();\n  } catch (InstantiationException exception) {\n    return null;\n  } catch (IllegalAccessException exception) {\n    return null;\n  }\n}\n\n```\n\nOriginal issue reported on code.google.com by `an...@google.com` on 15 Dec 2010 at 10:28"}}