PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Atlassian.Jira/Remote/RemoteIssueJsonConverter.cs

https://bitbucket.org/farmas/atlassian.net-sdk
C# | 186 lines | 146 code | 29 blank | 11 comment | 23 complexity | 50f0671630bdaefd716108df05cedcea MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using Newtonsoft.Json;
  7. using Newtonsoft.Json.Linq;
  8. namespace Atlassian.Jira.Remote
  9. {
  10. public class RemoteIssueWrapper
  11. {
  12. public RemoteIssueWrapper(RemoteIssue remoteIssue, string parentIssueKey = null)
  13. {
  14. RemoteIssue = remoteIssue;
  15. ParentIssueKey = parentIssueKey;
  16. }
  17. public RemoteIssue RemoteIssue { get; private set; }
  18. public string ParentIssueKey { get; private set; }
  19. }
  20. public class RemoteIssueJsonConverter : JsonConverter
  21. {
  22. private readonly IEnumerable<RemoteField> _remoteFields;
  23. private readonly IDictionary<string, ICustomFieldValueSerializer> _customFieldSerializers;
  24. public RemoteIssueJsonConverter(IEnumerable<RemoteField> remoteFields, IDictionary<string, ICustomFieldValueSerializer> customFieldSerializers)
  25. {
  26. this._remoteFields = remoteFields;
  27. this._customFieldSerializers = customFieldSerializers;
  28. }
  29. public override bool CanConvert(Type objectType)
  30. {
  31. return objectType == typeof(RemoteIssueWrapper);
  32. }
  33. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  34. {
  35. var issueObj = JObject.Load(reader);
  36. var fields = issueObj["fields"] as JObject;
  37. // deserialize the RemoteIssue from the fields json.
  38. var textReader = new JsonTextReader(new StringReader(fields.ToString()));
  39. var remoteIssue = serializer.Deserialize<RemoteIssue>(textReader);
  40. // set the id and key of the remoteissue.
  41. remoteIssue.id = (string)issueObj["id"];
  42. remoteIssue.key = (string)issueObj["key"];
  43. // load identifiers of JiraUsers
  44. remoteIssue.assignee = remoteIssue.assigneeJiraUser?.InternalIdentifier;
  45. remoteIssue.reporter = remoteIssue.reporterJiraUser?.InternalIdentifier;
  46. // load the custom fields
  47. var customFields = GetCustomFieldValuesFromObject(fields);
  48. remoteIssue.customFieldValues = customFields.Any() ? customFields.ToArray() : null;
  49. // save fields dictionary
  50. remoteIssue.fieldsReadOnly = fields;
  51. return new RemoteIssueWrapper(remoteIssue);
  52. }
  53. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  54. {
  55. var issueWrapper = value as RemoteIssueWrapper;
  56. if (issueWrapper == null)
  57. {
  58. throw new InvalidOperationException(String.Format("value must be of type {0}.", typeof(RemoteIssueWrapper)));
  59. }
  60. var issue = issueWrapper.RemoteIssue;
  61. // prepare the JiraUser identifiers
  62. issue.assigneeJiraUser = String.IsNullOrEmpty(issue.assignee) ? null : new JiraUser() { InternalIdentifier = issue.assignee };
  63. issue.reporterJiraUser = String.IsNullOrEmpty(issue.reporter) ? null : new JiraUser() { InternalIdentifier = issue.reporter };
  64. // Round trip the remote issue to get a JObject that has all the fields in the proper format.
  65. var issueJsonBuilder = new StringBuilder();
  66. var textWriter = new JsonTextWriter(new StringWriter(issueJsonBuilder));
  67. serializer.Serialize(textWriter, issue);
  68. var issueJson = issueJsonBuilder.ToString();
  69. var fields = JObject.Parse(issueJson);
  70. // Add the custom fields as additional JProperties.
  71. AddCustomFieldValuesToObject(issue, fields);
  72. // Add a field for the parent issue if this is a sub-task
  73. if (!String.IsNullOrEmpty(issueWrapper.ParentIssueKey))
  74. {
  75. fields.Add("parent", JObject.FromObject(new
  76. {
  77. key = issueWrapper.ParentIssueKey
  78. }));
  79. }
  80. var wrapper = new JObject(new JProperty("fields", fields));
  81. wrapper.WriteTo(writer);
  82. }
  83. private string GetCustomFieldType(string customFieldId)
  84. {
  85. var remoteField = this._remoteFields.FirstOrDefault(f => f.id.Equals(customFieldId, StringComparison.InvariantCultureIgnoreCase));
  86. return remoteField != null && remoteField.Schema.Custom != null ? remoteField.Schema.Custom : "SDK-Unknown-Field-Type";
  87. }
  88. private void AddCustomFieldValuesToObject(RemoteIssue remoteIssue, JObject jObject)
  89. {
  90. if (remoteIssue.customFieldValues != null)
  91. {
  92. foreach (var customField in remoteIssue.customFieldValues)
  93. {
  94. if (customField.values != null)
  95. {
  96. var customFieldType = GetCustomFieldType(customField.customfieldId);
  97. JToken jToken;
  98. if (this._customFieldSerializers.ContainsKey(customFieldType))
  99. {
  100. jToken = this._customFieldSerializers[customFieldType].ToJson(customField.values);
  101. }
  102. else if (customField.serializer != null)
  103. {
  104. jToken = customField.serializer.ToJson(customField.values);
  105. }
  106. else if (customField.values.Length > 0)
  107. {
  108. jToken = JValue.CreateString(customField.values[0]);
  109. }
  110. else
  111. {
  112. jToken = new JArray();
  113. }
  114. jObject.Add(customField.customfieldId, jToken);
  115. }
  116. }
  117. }
  118. }
  119. private IEnumerable<RemoteCustomFieldValue> GetCustomFieldValuesFromObject(JObject jObject)
  120. {
  121. return jObject.Values<JProperty>()
  122. .Where(field => field.Name.StartsWith("customfield", StringComparison.InvariantCulture) && field.Value.Type != JTokenType.Null)
  123. .Select(field =>
  124. {
  125. var customFieldType = GetCustomFieldType(field.Name);
  126. var remoteCustomFieldValue = new RemoteCustomFieldValue()
  127. {
  128. customfieldId = field.Name,
  129. rawValue = field.Value
  130. };
  131. if (this._customFieldSerializers.ContainsKey(customFieldType))
  132. {
  133. remoteCustomFieldValue.values = this._customFieldSerializers[customFieldType].FromJson(field.Value);
  134. }
  135. else if (field.Value.Type == JTokenType.Array)
  136. {
  137. var serializer = new MultiStringCustomFieldValueSerializer();
  138. try
  139. {
  140. remoteCustomFieldValue.values = serializer.FromJson(field.Value);
  141. }
  142. catch (JsonReaderException)
  143. {
  144. // If deserialization failed, then it is not an array of strings, it is not known how to
  145. // deserialize this field and treat is a black box and dump the json into the property.
  146. remoteCustomFieldValue.values = new string[1] { field.Value.ToString() };
  147. }
  148. }
  149. else
  150. {
  151. remoteCustomFieldValue.values = new string[1] { field.Value.ToString() };
  152. }
  153. return remoteCustomFieldValue;
  154. });
  155. }
  156. }
  157. }