Reputation: 84
I have three classes
class Device{
name:string;
}
class Mobile extends Device{
number:string;
}
class Computer extends Device{
macAddress:string;
}
and json
[{
'name':'mobile1',
'number':'600 600 600',
'class':'Mobile'
},{
'name':'computer',
'macAddress:'123123123',
'class':'Computer'
}]
is it possible using some kind of decorators/or anything else to get List of devices with correct object types. I'm producting Json at my site so i can also add another fields, change structure to make typescript object list generate corectly
I was searching for any solution without success.
Regards, Adrian
Upvotes: 0
Views: 3739
Reputation: 84
I've based my solution on what andreas wrote thank You. To achieve proper solution i've used aswesome library json2typescript . My Solution:
import {JsonObject, JsonProperty, JsonConverter, JsonCustomConvert, JsonConvert} from "json2typescript";
@JsonConverter
class DeviceConverter implements JsonCustomConvert<DeviceDto[]> {
// We receive the instance and just serialize it with the standard json2typescript method.
serialize(device: DeviceDto[]): any {
const jsonConvert: JsonConvert = new JsonConvert();
return jsonConvert.serialize(device);
}
// We receive a json object (not string) and decide
// based on the given properties whether we want to
// create an instance of Computer or Mobile.
deserialize(devicesInput: any): DeviceDto[] {
const jsonConvert: JsonConvert = new JsonConvert();
let devices: Array<DeviceDto> = new Array<DeviceDto>();
for (let device of devicesInput) {
if (device['type'] == 'mobile') {
let temp:MobileDeviceDto=jsonConvert.deserialize(device, MobileDeviceDto)
devices.push(temp);
} else if (device['type'] == 'rpi') {
devices.push(jsonConvert.deserialize(device, RaspberryPiDeviceDto));
}
}
return devices;
}
}
@JsonObject
export class DevicesDto {
@JsonProperty("devices", DeviceConverter)
devices: DeviceDto[] = [];
}
@JsonObject
export class DeviceDto {
@JsonProperty("name", String)
name: string= undefined;
@JsonProperty("description", String)
description: string= undefined;
@JsonProperty("type", String)
type: string= undefined;
}
@JsonObject
export class MobileDeviceDto extends DeviceDto {
@JsonProperty("number", String)
number: string = undefined;
}
@JsonObject
export class RaspberryPiDeviceDto extends DeviceDto {
@JsonProperty("version", String)
version: string = undefined;
}
Usage:
let jsonConvert: JsonConvert = new JsonConvert();
let devices: DeviceDto[] = jsonConvert.deserialize(data, DevicesDto).devices;
this.subjectDeviceList.next(data);
Thank You very much :)
Upvotes: 1
Reputation: 8004
I would suggest the following implementation. Please note the comments inside. It might contain some errors because I cannot actually check the code, so maybe some more work is necessary.
Basic idea: To make code simple in your components, you should wrap your array into an object, here called JsonDevices. Then you can write a custom converter and let the magic happen inside the converter.
Classes
// Custom serializer/deserializer.
// You must implement serialize and deserialize methods
@JsonConverter
class DeviceConverter implements JsonCustomConvert<Device> {
// We receive the instance and just serialize it with the standard json2typescript method.
serialize(device: Device): any {
const jsonConvert: JsonConvert = new JsonConvert();
return jsonConvert.serialize(device);
}
// We receive a json object (not string) and decide
// based on the given properties whether we want to
// create an instance of Computer or Mobile.
deserialize(device: any): Device {
const jsonConvert: JsonConvert = new JsonConvert();
// We need the try/catch because of deserialize inside
try {
if (device.name && device.macAddress) {
const computer: Computer = new Computer();
computer.name = device.name;
computer.macAddress = device.macAddress;
return jsonConvert.deserialize(computer, Computer);
} else if (device.name && device.number)
const mobile: Mobile = new Mobile();
mobile.name = device.name;
mobile.number = device.number;
return jsonConvert.deserialize(mobile, Mobile);
}
} catch(e) {}
throw new TypeError();
}
}
@JsonObject
class JsonDevices {
@JsonProperty("devices", DeviceConverter)
devices: Device[] = [];
}
@JsonObject
class Device {
@JsonProperty("name", String)
name: string = undefined;
}
@JsonObject
class Mobile extends Device {
@JsonProperty("number", String)
number: string = undefined;
}
@JsonObject
class Computer extends Device {
@JsonProperty("macAddress", String)
macAddress: string = undefined;
}
Usage
// Assume this is your incoming json
const jsonString: string = ("
[{
'name':'mobile1',
'number':'600 600 600',
'class':'Mobile'
},{
'name':'computer',
'macAddress:'123123123',
'class':'Computer'
}]
");
// Convert it to an JSON/JavaScript object
// In the current Angular 4 HttpClientModule API,
// you would get an object directly and you wouldn't
// bother with it anyway.
const jsonArray: any[] = JSON.parse(jsonString);
// Make sure the given array is added to an object
// having a device array
const jsonDevicesObject: any = {
devices: jsonArray;
}
// Now deserialize the whole thing with json2typescript:
const jsonConvert: JsonConvert = new JsonConvert();
const jsonDevices: JsonDevices = jsonConvert.deserialize(jsonDevicesObject, JsonDevices);
// Now all elements of jsonDevices.devices are of instance Mobile or Computer
Upvotes: 1