toJson method throws stackOverflow - dart

from backend I'm receiving json that looks like this
{
"teamDto": {
"id": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"teamName": "tasdasd",
"payPerPractice": 123.0,
"payPerGame": 123.0,
"season": "asdasd",
"teamMembers": [
{
"id": "4657dd50-974c-427c-8e77-0f5e1f4fd23c",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "6a758edd-fbac-49b5-bed4-250c585b5c3f",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "98786a8a-3915-4e3a-b832-32fc6c4d8b8d",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "c3e76455-a7bb-4be4-abe7-09436f6fe3df",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
}
],
"sport": null
},
"owner": true,
"manager": true
}
I'm aware of imperfections in my json, but thats not the problem.
The problem is when i try to convert it to object, my programm throws stackoverflow.
Here is my TeamDashboardDtoclass
class TeamDashboardDto{
late TeamDto teamDto;
late bool isOwner;
late bool isManager;
TeamDashboardDto({required this.teamDto, required this.isOwner, required this.isManager});
factory TeamDashboardDto.fromJson(Map<String, dynamic> json) => TeamDashboardDto.fromJson(json);
Map<String, dynamic> toJson() => UserAndTeamDtoToJson(this);
Map<String, dynamic> UserAndTeamDtoToJson(TeamDashboardDto instance) => <String, dynamic>{
'teamDto': instance.teamDto,
'owner': instance.isOwner,
'manager': instance.isManager,
};
}
and here is my TeamDto class
class TeamDto{
String? id;
String? teamName;
double? payPerPractice;
double? payPerGame;
String? season;
List<TeamMemberDto>? teamMembers;
TeamDto({this.id, this.teamName, this.payPerGame, this.payPerPractice, this.season, this.teamMembers});
factory TeamDto.fromJson(Map<String, dynamic> json) {
return TeamDto(
id: json['id'],
teamName: json['teamName'],
payPerPractice: json['payPerPractice'],
payPerGame: json['payPerGame'],
season: json['season'],
teamMembers: List<TeamMemberDto>.from(
json['teamMembers'].map((model) => TeamMemberDto.fromJson(model)))
);
}
Map<String, dynamic> toJson() => {
'id': id,
'teamName': teamName,
'sport': sport,
'payPerGame': payPerGame,
"payPerPractice": payPerPractice,
"season": season,
"teamMembers": teamMembers
};
}
I dont see why theres a problem because i have other Dto classes that contain two different dto's which one of them is TeamDto, the only difference here is that this dto class contains two booleans and another dto class instead of two dto classes.

You have an infinite call loop here:
factory TeamDashboardDto.fromJson(Map<String, dynamic> json)
=> TeamDashboardDto.fromJson(json);
So your TeamDashboardDto.fromJson factory are calling the TeamDashboardDto.fromJson factory which are calling the TeamDashboardDto.fromJson factory... and so on since it is just calling itself.

This code was generated by other small script.
Generation script was written in less than 5 minutes.
import 'dart:convert';
void main() {
final json = jsonDecode(_response) as Map;
final response = Response.fromJson(json);
print(response.teamDto.teamMembers[0].id);
}
const _response = '''
{
"teamDto": {
"id": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"teamName": "tasdasd",
"payPerPractice": 123.0,
"payPerGame": 123.0,
"season": "asdasd",
"teamMembers": [
{
"id": "4657dd50-974c-427c-8e77-0f5e1f4fd23c",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "6a758edd-fbac-49b5-bed4-250c585b5c3f",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "98786a8a-3915-4e3a-b832-32fc6c4d8b8d",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "c3e76455-a7bb-4be4-abe7-09436f6fe3df",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
}
],
"sport": null
},
"owner": true,
"manager": true
}''';
class Response {
Response({required this.teamDto, required this.owner, required this.manager});
factory Response.fromJson(Map json) {
return Response(
teamDto: TeamDto.fromJson(json['teamDto'] as Map),
owner: json['owner'] == null ? false : json['owner'] as bool,
manager: json['manager'] == null ? false : json['manager'] as bool,
);
}
final TeamDto teamDto;
final bool owner;
final bool manager;
static List<Response> fromJsonList(List json) {
return json.map((e) => Response.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'teamDto': teamDto.toJson(),
'owner': owner,
'manager': manager,
};
}
static List<Map<String, dynamic>> toJsonList(List<Response> list) {
return list.map((e) => e.toJson()).toList();
}
}
class TeamDto {
TeamDto(
{required this.id,
required this.teamName,
required this.payPerPractice,
required this.payPerGame,
required this.season,
required this.teamMembers,
required this.sport});
factory TeamDto.fromJson(Map json) {
return TeamDto(
id: json['id'] == null ? '' : json['id'] as String,
teamName: json['teamName'] == null ? '' : json['teamName'] as String,
payPerPractice: json['payPerPractice'] == null
? 0.0
: json['payPerPractice'] as double,
payPerGame:
json['payPerGame'] == null ? 0.0 : json['payPerGame'] as double,
season: json['season'] == null ? '' : json['season'] as String,
teamMembers: json['teamMembers'] == null
? []
: (json['teamMembers'] as List)
.map((e) => TeamMemberDto.fromJson(e as Map))
.toList(),
sport: json['sport'],
);
}
final String id;
final String teamName;
final double payPerPractice;
final double payPerGame;
final String season;
final List<TeamMemberDto> teamMembers;
final Object? sport;
static List<TeamDto> fromJsonList(List json) {
return json.map((e) => TeamDto.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'id': id,
'teamName': teamName,
'payPerPractice': payPerPractice,
'payPerGame': payPerGame,
'season': season,
'teamMembers': teamMembers.map((e) => e.toJson()).toList(),
'sport': sport,
};
}
static List<Map<String, dynamic>> toJsonList(List<TeamDto> list) {
return list.map((e) => e.toJson()).toList();
}
}
class TeamMemberDto {
TeamMemberDto(
{required this.id,
required this.isOwner,
required this.isManager,
required this.teamName,
required this.teamId,
required this.name,
required this.lastName});
factory TeamMemberDto.fromJson(Map json) {
return TeamMemberDto(
id: json['id'] == null ? '' : json['id'] as String,
isOwner: json['isOwner'] == null ? false : json['isOwner'] as bool,
isManager: json['isManager'] == null ? false : json['isManager'] as bool,
teamName: json['teamName'] == null ? '' : json['teamName'] as String,
teamId: json['teamId'] == null ? '' : json['teamId'] as String,
name: json['name'] as String?,
lastName: json['lastName'] as String?,
);
}
final String id;
final bool isOwner;
final bool isManager;
final String teamName;
final String teamId;
final String? name;
final String? lastName;
static List<TeamMemberDto> fromJsonList(List json) {
return json.map((e) => TeamMemberDto.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'id': id,
'isOwner': isOwner,
'isManager': isManager,
'teamName': teamName,
'teamId': teamId,
'name': name,
'lastName': lastName,
};
}
static List<Map<String, dynamic>> toJsonList(List<TeamMemberDto> list) {
return list.map((e) => e.toJson()).toList();
}
}
Generation script.
Models defined in simple YAML format.
It also includes an example template that can be easily removed.
import 'dart:io';
import 'package:object_serializer/json_serializer_generator.dart';
import 'package:yaml/yaml.dart';
void main() {
final classes = loadYaml(_classes) as Map;
final g = JsonSerializerGenerator();
final classesCode = g.generateClasses(classes);
final values = {
'classes': classesCode,
};
var source = g.render(_template, values);
source = g.format(source);
File('bin/stackoverflow.dart').writeAsStringSync(source);
}
const _classes = r'''
Response:
fields:
teamDto: TeamDto
owner: bool
manager: bool
TeamDto:
fields:
id: String
teamName: String
payPerPractice: double
payPerGame: double
season: String
teamMembers: List<TeamMemberDto>
sport: Object?
TeamMemberDto:
fields:
id: String
isOwner: bool
isManager: bool
teamName: String
teamId: String
name: String?
lastName: String?
''';
const _template = r"""
import 'dart:convert';
void main() {
final json = jsonDecode(_response) as Map;
final response = Response.fromJson(json);
print(response.teamDto.teamMembers[0].id);
}
const _response =
'''
{
"teamDto": {
"id": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"teamName": "tasdasd",
"payPerPractice": 123.0,
"payPerGame": 123.0,
"season": "asdasd",
"teamMembers": [
{
"id": "4657dd50-974c-427c-8e77-0f5e1f4fd23c",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "6a758edd-fbac-49b5-bed4-250c585b5c3f",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "98786a8a-3915-4e3a-b832-32fc6c4d8b8d",
"isOwner": true,
"isManager": true,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
},
{
"id": "c3e76455-a7bb-4be4-abe7-09436f6fe3df",
"isOwner": false,
"isManager": false,
"teamName": "tasdasd",
"teamId": "34ec8e71-b5a9-4a4c-b461-5cbb562329b5",
"name": null,
"lastName": null
}
],
"sport": null
},
"owner": true,
"manager": true
}''';
{{classes}}
""";

Related

Group a list of json object by property inside the common array using iOS Swift

I would like to ask if how to group the object by another object inside its common array based on the id in Swift.
Here's the JSON response, I need to group the list of the item by program id.
{
"id": "",
"ordered_by": 64,
"order_details": [
{
"resource": "Product",
"required_prescription": false,
"item": {
"id": 6,
"name": "Synergistic Copper Gloves",
"code": "51537661-C",
"enabled": true,
"generic_name": "Mediocre Steel Wallet",
"price_cents": 200000
},
"program": {
"id": 12, <----PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed"
}
},
{
"resource": "Product",
"required_prescription": true,
"item": {
"id": 7,
"name": "Rustic Leather Table",
"code": "74283131-P",
"enabled": true,
"generic_name": "Incredible Bronze Clock",
"price_cents": 8994
},
"program": {
"id": 12, <----PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed"
}
},
{
"resource": "Product",
"required_prescription": false,
"item": {
"id": 116,
"name": "Ergonomic Marble Hat",
"code": "98845056-A",
"enabled": true,
"generic_name": "Incredible Granite Lamp",
"price_cents": 8267
},
"program": {
"id": 10, <----PROGRAM ID
"name": "Durable Rubber Bag",
"provider": "Aerodynamic Steel Chair",
"discount_type": "fixed"
}
}
]}
For example, the item with program id 12 should be inserted under its common program.
This should be the expected object after grouping. The item was grouped by program id 12 & 10.
[
{
"id": 12, <----- PROGRAM ID
"name": "Synergistic Wooden Shoes",
"provider": "Synergistic Rubber Coat",
"discount_type": "fixed",
"item": [
{
"id": 6,
"name": "Synergistic Copper Gloves",
"code": "51537661-C",
"enabled": true,
"generic_name": "Mediocre Steel Wallet",
"price_cents": 200000
},
{
"id": 7,
"name": "Rustic Leather Table",
"code": "74283131-P",
"enabled": true,
"generic_name": "Incredible Bronze Clock",
"price_cents": 8994
}
]
},
{
"id": 10, <----PROGRAM ID
"name": "Durable Rubber Bag",
"provider": "Aerodynamic Steel Chair",
"discount_type": "fixed",
"item": [
{
"id": 116,
"name": "Ergonomic Marble Hat",
"code": "98845056-A",
"enabled": true,
"generic_name": "Incredible Granite Lamp",
"price_cents": 8267
}
]
}
]
I've successfully made it in Java using the sample code below:
private String parseJson(String source) {
JSONArray result = new JSONArray();
List<Integer> ids = new ArrayList<>();
HashMap<Integer,JSONObject> programs = new HashMap<>();
try {
JSONObject jSource = new JSONObject(source);
JSONArray orderDetails = jSource.getJSONArray("order_details");
if (orderDetails.length() > 0) {
for (int i = 0; i < orderDetails.length(); i++) {
JSONObject jsonObject = orderDetails.getJSONObject(i);
JSONObject item = jsonObject.getJSONObject("item");
JSONObject program = jsonObject.getJSONObject("program");
int programId = jsonObject.getJSONObject("program").getInt("id");
if (!ids.contains(programId)) {
ids.add(programId);
program.put("item",new JSONArray().put(item));
programs.put(programId,program);
}else{
program.put("item",programs.get(programId).getJSONArray("item").put(item));
}
}
for(int k :programs.keySet()){
result.put(programs.get(k));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}
I'm trying to replicate it on swift but I'm looking for a different approach, not the same approach as I did in Java. I tried to used reduce and filter method but it doesn't work.
Any answer would be hight appreciated.
Thanks
Few comments on an answer from #omerfarukozturk,
Flatmap is deprecated so you can use map or compactMap.
In omerfarukozturk's answer he returns only program id while grouping which is not as per requirement, we need whole program details instead of just Id
So I have applied some other logic.
Bind data with model
let arrDetails = //Bind data with model, response.orderDetails
Get Unique program ID
let arrProgramID = arrDetails.compactMap{ $0.program }.removingDuplicates(byKey: \.id)
// removingDuplicates is logic for remove duplicate programs and have unique program array with all information
Bind array in [[Program: [Item]]] form
let finalArray = arrProgram.map { (program) -> [Program: [Item]] in
let arr = arrDetails.filter{ $0.program.id == program.id }.compactMap{ $0.item }
return [program: arr]
}
Adding extension for removing duplicates
extension Array {
func removingDuplicates<T: Equatable>(byKey key: KeyPath<Element, T>) -> [Element] {
var result = [Element]()
var seen = [T]()
for value in self {
let key = value[keyPath: key]
if !seen.contains(key) {
seen.append(key)
result.append(value)
}
}
return result
}
}
You can use Dictionary(grouping:) to group a list. Not completely answer, but for your case you can create a logic like below;
Assume you have a decoded response model as response for your json.
let flatttenOrderDetails = response.order_details.flatMap( { $0 })
let grouped = Dictionary(grouping: flatttenOrderDetails, by: { (element: Detail) in
return element.program.id
})
I was able to group the JSON based on its common program id by creating another model ProgramWith items.
struct ProgramWithItems: Codable {
let id: Int?
let name: String?
let provider: String?
let discountType: String?
let resource: String?
let discount: String?
let item: [Item]
}
Then I used the reduce method and populate the ProgramWithItems model using the code below:
func groupItems(_ response: CartEntity.Response) -> [ProgramWithItems] {
response.orderDetails!.reduce(into: []) { (result: inout [ProgramWithItems], detail: OrderDetail) in
guard let index = result.firstIndex(where: { $0.id == detail.program?.id }) else {
var item = detail.item
item?.quantity = detail.quantity
item?.costCents = detail.cost_cents
let newProgram = ProgramWithItems(
id: detail.program?.id,
name: detail.program?.name ?? "",
provider: detail.program?.provider ?? "",
discountType: detail.program?.discountType ?? "",
resource: detail.resource ?? "",
discount: detail.program?.discount,
item: [item!])
result.append(newProgram)
return
}
let existingProgram = result[index]
var item = detail.item
item?.quantity = detail.quantity
item?.costCents = detail.cost_cents
let extendedProgram = ProgramWithItems(
id: existingProgram.id,
name: existingProgram.name,
provider: existingProgram.provider,
discountType: existingProgram.discountType,
resource: detail.resource ?? "",
discount: detail.program?.discount,
item: existingProgram.item + [item!])
result[index] = extendedProgram
}
}

How to iterate through array to pull out properties for specifc keys?

Im working with decoded JSON, and specifically i need to work within an array to pull out a property of a specific object based on its key.
JSON looks like the following, and Im needing to pull out the filenames for "fanart" and "clearlogo"
{
"code": 200,
"status": "Success",
"data": {
"count": 1,
"base_url": {
"original": "https://cdn.thegamesdb.net/images/original/",
"small": "https://cdn.thegamesdb.net/images/small/",
"thumb": "https://cdn.thegamesdb.net/images/thumb/",
"cropped_center_thumb": "https://cdn.thegamesdb.net/images/cropped_center_thumb/",
"medium": "https://cdn.thegamesdb.net/images/medium/",
"large": "https://cdn.thegamesdb.net/images/large/"
},
"images": {
"2578": [
{
"id": 5512,
"type": "boxart",
"side": "front",
"filename": "boxart/front/2578-1.jpg",
"resolution": "1533x2155"
},
{
"id": 5513,
"type": "boxart",
"side": "back",
"filename": "boxart/back/2578-1.jpg",
"resolution": "1522x2155"
},
{
"id": 87092,
"type": "fanart",
"side": null,
"filename": "fanart/2578-1.jpg",
"resolution": "1920x1080"
},
{
"id": 87093,
"type": "fanart",
"side": null,
"filename": "fanart/2578-2.jpg",
"resolution": "1920x1080"
},
{
"id": 87094,
"type": "fanart",
"side": null,
"filename": "fanart/2578-3.jpg",
"resolution": "1920x1080"
},
{
"id": 87095,
"type": "clearlogo",
"side": null,
"filename": "clearlogo/2578.png",
"resolution": "400x300"
},
{
"id": 87096,
"type": "screenshot",
"side": null,
"filename": "screenshots/2578-1.jpg",
"resolution": null
},
{
"id": 87097,
"type": "screenshot",
"side": null,
"filename": "screenshots/2578-2.jpg",
"resolution": null
},
{
"id": 87098,
"type": "fanart",
"side": null,
"filename": "fanart/2578-4.jpg",
"resolution": "1920x1080"
},
{
"id": 87099,
"type": "screenshot",
"side": null,
"filename": "screenshots/2578-3.jpg",
"resolution": null
},
{
"id": 87100,
"type": "screenshot",
"side": null,
"filename": "screenshots/2578-4.jpg",
"resolution": null
},
{
"id": 87101,
"type": "fanart",
"side": null,
"filename": "fanart/2578-5.jpg",
"resolution": "1920x1080"
}
]
}
},
The key "2578"is dynamic and changes by the game. I have this succesfuly decoding with the following:
struct GameDBData : Decodable {
let data : GameDataImages
}
struct GameDataImages : Decodable {
let images : Images
}
struct Images : Decodable {
var innerArray: [String: [Inner]]
struct Inner: Decodable {
let id : Int
let fileName : String
let type : String
enum CodingKeys : String, CodingKey {
case id
case fileName = "filename"
case type
}
}
private struct CustomCodingKeys: CodingKey {
var stringValue : String
init?(stringValue : String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CustomCodingKeys.self)
self.innerArray = [String: [Inner]]()
for key in container.allKeys {
let value = try container.decode([Inner].self, forKey: CustomCodingKeys(stringValue: key.stringValue)!)
self.innerArray[key.stringValue] = value
}
}
}
Ive tried firstIndex(where:) but Im not getting anywhere with it. How can i iterate the 2578 array to get the filename for type: "clearlogo" and type: "fanart" im needing?
You have array of Inner.Something like this,
var array:[Inner] = [_yourData]
If we assume your array should have only one object with type "fanart" & "clearlogo" for each.we can get each filename using ,
let fanartFileName = array.filter({$0.type == "fanart"})[0].fileName
let clearlogoFileName = array.filter({$0.type == "clearlogo"})[0].fileName
some times your array havn't any record for these types.or have more than one,
let fanartArray = ar.filter({$0.type == "fanart"})
if fanartArray.count > 0 {
fanartArray.forEach { (record) in
print(record.fileName)
}
}

Get OData option set values and names

I am using odata api, now I have an attribute on an entity that is an option select like :
attribute name is : status
values are: 1, 2, 3
names: done, progress, new
the thing is when I am using postman to fetch metadata and all I get for the fields 'status' its that its type integer.
Question how do I fetchj option names and values from metadata so I get values and names in response ?
Currently I get this:
<Property Name="status" Type="Edm.Int32">
<Annotation Term="Org.OData.Core.V1.Description" String="" />
</Property>
But I want to get the value and names on response ?
This could be vastly simplified, assuming all you want are the int values, and names for a particular option set attribute of an entity:
GET [Organization URI]/api/data/v8.2/EntityDefinitions(LogicalName='contact')/Attributes(LogicalName='status')/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName&$expand=OptionSet($select=Options),GlobalOptionSet($select=Options)
The $select=LogicalName is just so it doesn't return all the other metadata for the attribute, and the $expand=OptionSet($select=Options) is for local option sets, and the GlobalOptionSet($select=Options) is for Global. If you know what type it is, you can skip it the other, but if you are putting this logic in a shared library (you are aren't you?) then adding both won't hurt:
{
"#odata.context":"http://YourOrg.com/YourInstance/api/data/v8.2/$metadata#EntityDefinitions('new_entity')/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata(LogicalName,OptionSet,GlobalOptionSet,OptionSet(Options),GlobalOptionSet(Options))/$entity",
"LogicalName":"new_familyshortname",
"MetadataId":"dc11c01f-b6bd-4664-82d0-3a521841c1f5",
"OptionSet#odata.context":"http://YourOrg.com/YourInstance/api/data/v8.2/$metadata#EntityDefinitions('new_entity')/Attributes(dc11c01f-b6bd-4664-82d0-3a521841c1f5)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet(Options)/$entity",
"OptionSet":null,
"GlobalOptionSet":{
"#odata.type":"#Microsoft.Dynamics.CRM.OptionSetMetadata",
"Options":[
{
"Value":117280000,
"Label":{
"LocalizedLabels":[
{
"Label":"English Value 1",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3cb6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
},
{
"Label":"French Value 1",
"LanguageCode":1036,
"IsManaged":false,
"MetadataId":"d88be67d-4a7d-e411-8890-0050569f1654",
"HasChanged":null
}
],
"UserLocalizedLabel":{
"Label":"English Value 1",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3cb6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
},
"Description":{
"LocalizedLabels":[
{
"Label":"",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3db6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
],
"UserLocalizedLabel":{
"Label":"",
"LanguageCode":1033,
"IsManaged":true,
"MetadataId":"3db6bbd5-796f-e111-8cf3-3cd92b023782",
"HasChanged":null
}
},
"Color":null,
"IsManaged":true,
"MetadataId":null,
"HasChanged":null
},
... MORE ...
],
"MetadataId":"dcbbe460-bedb-4985-9a17-2f3dbc637594"
}
}
According to this article this is a multi-step process.
Please note that all the examples use HTTP GET.
First retrieve the entity's MetaData Id (for this example we're using the entity 'account'):
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions?$select=LogicalName,MetadataId&$filter=LogicalName eq 'account'
Returns:
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(LogicalName,MetadataId)",
"value": [{
"LogicalName": "account",
"MetadataId": "70816501-edb9-4740-a16c-6a5efbc05d84"
}]
}
Then retrieve the attribute's MetaDataId (in this example we're using the option set 'customertypecode'):
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)?$select=LogicalName&$expand=Attributes($select=LogicalName;$filter=LogicalName eq 'customertypecode')
Returns:
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(LogicalName,Attributes(LogicalName))/$entity",
"LogicalName": "account",
"MetadataId": "70816501-edb9-4740-a16c-6a5efbc05d84",
"Attributes#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(LogicalName)",
"Attributes": [{
"#odata.type": "#Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
"LogicalName": "customertypecode",
"MetadataId": "4e33af09-ba43-4365-a747-c7e4f9992172"
}]
}
Then query with the entity's and attribute's MetadataIds to get the option set values:
https://myOrg.crm.dynamics.com/api/data/v8.2/EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(4e33af09-ba43-4365-a747-c7e4f9992172)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata?$select=LogicalName&$expand=OptionSet
Returns (truncated at 2 values):
{
"#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes/Microsoft.Dynamics.CRM.PicklistAttributeMetadata(LogicalName,OptionSet)/$entity",
"LogicalName": "customertypecode",
"MetadataId": "4e33af09-ba43-4365-a747-c7e4f9992172",
"OptionSet#odata.context": "https://myOrg.crm.dynamics.com/api/data/v8.2/$metadata#EntityDefinitions(70816501-edb9-4740-a16c-6a5efbc05d84)/Attributes(4e33af09-ba43-4365-a747-c7e4f9992172)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet/$entity",
"OptionSet": {
"MetadataId": "3629e642-b895-41ab-8f1d-ea5bfa30e992",
"HasChanged": null,
"IsCustomOptionSet": false,
"IsGlobal": false,
"IsManaged": true,
"Name": "account_customertypecode",
"ExternalTypeName": null,
"OptionSetType": "Picklist",
"IntroducedVersion": "5.0.0.0",
"Description": {
"LocalizedLabels": [{
"Label": "Type of the account.",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "73f68e38-c78d-48a5-80cb-bee895baab2b",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Type of the account.",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "73f68e38-c78d-48a5-80cb-bee895baab2b",
"HasChanged": null
}
},
"DisplayName": {
"LocalizedLabels": [{
"Label": "Relationship Type",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "e5d47366-fd09-41e6-96a1-cbfdd113b932",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Relationship Type",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "e5d47366-fd09-41e6-96a1-cbfdd113b932",
"HasChanged": null
}
},
"IsCustomizable": {
"Value": true,
"CanBeChanged": false,
"ManagedPropertyLogicalName": "iscustomizable"
},
"Options": [{
"Value": 1,
"Color": null,
"IsManaged": true,
"ExternalValue": null,
"MetadataId": null,
"HasChanged": null,
"Label": {
"LocalizedLabels": [{
"Label": "Competitor",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6c54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Competitor",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6c54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}
},
"Description": {
"LocalizedLabels": [],
"UserLocalizedLabel": null
}
},
{
"Value": 2,
"Color": null,
"IsManaged": true,
"ExternalValue": null,
"MetadataId": null,
"HasChanged": null,
"Label": {
"LocalizedLabels": [{
"Label": "Consultant",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6e54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}],
"UserLocalizedLabel": {
"Label": "Consultant",
"LanguageCode": 1033,
"IsManaged": true,
"MetadataId": "6e54c2fa-2241-db11-898a-0007e9e17ebd",
"HasChanged": null
}
},
"Description": {
"LocalizedLabels": [],
"UserLocalizedLabel": null
}
}
}
}

How to provide string array (default values) in the swagger definition

Currently, my swagger definition has :
"MyAttribute": {
"type": "string",
"default": "item1",
"enum": [
"item1",
"item2"
],
"xml": {
"attribute": true
}
},
Swagger codegen generates this java code:
#XmlEnum(String.class)
public enum MyAttribute{
#XmlEnumValue("item1")
item1("item1"),
#XmlEnumValue("item2")
item2("item2");
private String value;
/**
* #param value the string representation of the map specification type attribute
*/
MyAttribute(final String value) {
this.value = value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}
Now, I want to have a string array(with values) instead of enum.
I tried this (but shows errors on swagger website : http://editor.swagger.io/)
"MyAttribute": {
"type": "array",
"items": {
"type": "string",
"values": [
"item1",
"item2"
]
},
"xml": {
"attribute": true
}
}
How to achieve this?

How to store business ID in elasticsearch?

I'm trying to store tweets in some Elasticsearch index using Spring Data Elasticsearch (for tweet requesting , I'm using twitter4j).
I have followed some basic example and I'm using this basic annotated POJO (metadatas with complex type have been removed) :
#Document(indexName = "twitter", type = "tweet")
public class StorableTweet {
#Id
private long id;
private String createdAt;
private String text;
private String source;
private boolean isTruncated;
private long inReplyToStatusId;
private long inReplyToUserId;
private boolean isFavorited;
private boolean isRetweeted;
private int favoriteCount;
private String inReplyToScreenName;
private String userScreenName = null;
// Getters/setters removed
}
To store a tweet using this model, I use :
public interface TweetRepository extends ElasticsearchRepository<StorableTweet, Long> {
}
and in my storing service :
tweetRepository.save(storableTweet);
It works fine, but my tweet Id is stored in "_id" (why not) and some other number coming from nowhere is stored in "id" (why....?) :
{
"_index": "twitter",
"_type": "tweet",
**"_id": "655008947099840512"**, <-- this is the real tweet id
"_version": 1,
"found": true,
"_source":
{
**"id": 655008947099840500**, <-- this number comes from nowhere
"createdAt": "Fri Oct 16 15:14:37 CEST 2015",
"text": "tweet text(...)",
"source": "Twitter for iPhone",
"inReplyToStatusId": -1,
"inReplyToUserId": -1,
"favoriteCount": 0,
"inReplyToScreenName": null,
"user": "971jml",
"favorited": false,
"retweeted": false,
"truncated": false
}
}
What I would like is either my tweet id stored in "_id" (and no "id" field), either my tweet id stored in "id" an having a generated number in "_id", and get rid of this random useless number in "id".
EDIT
mapping :
{
"twitter":
{
"mappings":
{
"tweet":
{
"properties":
{
"createdAt":
{
"type": "string"
},
"favoriteCount":
{
"type": "long"
},
"favorited":
{
"type": "boolean"
},
"inReplyToScreenName":
{
"type": "string"
},
"inReplyToStatusId":
{
"type": "long"
},
"inReplyToUserId":
{
"type": "long"
},
"retweeted":
{
"type": "boolean"
},
"source":
{
"type": "string"
},
"text":
{
"type": "string"
},
"truncated":
{
"type": "boolean"
},
"tweetId":
{
"type": "long"
},
"user":
{
"type": "string"
}
}
}
}
}
}
EDIT 2 : It looks like the problem is not about #Id annotation but about "long" type. Some other longs (not all) are transformed (a few units more or less) when stored into elasticsearch via Spring Data Elasticsearch.

Resources