shakilsiraj / json-object-mapper Goto Github PK
View Code? Open in Web Editor NEWA TypeScript library to serialize and deserialize object graph from/to JSON in a fast and non-recursive way
License: MIT License
A TypeScript library to serialize and deserialize object graph from/to JSON in a fast and non-recursive way
License: MIT License
Example from Readme doesn't work properly with TypeScript.
It should be updated or have info about that all classess used by object mapper must be created with constructor or marked all fields as undefined
Hi,
firstly, thanks for the library - it fits my needs perfectly, however I have encountered a couple of blockers related to the caching of custom de/serializer objects.
From my debugging, it seems that the caching logic uses a function over the string representation of the instantiation method of de/serializer. Under the following circumstances, this results in the incorrect de/serializer being used:
As I use a lot of ES6 Maps / Sets in my project, I wrote a generic marshalling class to deal with the de/serialisation of the collection. However, the identifier used for the entry into the cache map does not include the generic type specifier.
Example:
Given the following generic Set deserializer definition:
export class SetMarshaller<EntryType> implements Deserializer, Serializer {
type: {new (): EntryType};
public constructor(type: {new (): EntryType}) {
this.type = type;
}
public deserialize(values: string[]): Set<EntryType> {
const setToReturn: Set<EntryType> = new Set();
if (values) {
values.forEach(entry => {
setToReturn.add(ObjectMapper.deserialize(this.type, entry));
});
}
return setToReturn;
}
public serialize(value: Set<EntryType>): string {
const results = [];
value.forEach(entry => {
let obj: any = entry;
if (isObject(entry)) {
obj = ObjectMapper.serialize(entry).toString();
}
results.push(JSON.parse(obj));
});
return JSON.stringify(results);
}
}
Both of the following instantiations will result in the same identifier being used in the cache map:
SetMarshaller<MyCusomObject1>; // identifier: 'SetMarshaller'
SetMarshaller<YetAnotherCustomObject>; // identifier: 'SetMarshaller'
This will result in every set marshaller using the instanced used for the first encountered SetMashaller during execution of the app.
The identity mechanism shows interesting behaviour when running a production build generated by angular-cli.
Specifically, the minification and uglification mechanism replaces the named constructors with generated functions, which obscures the actual name of the construction function, resulting in more frequent clashes in the caching mechanism.
Is it possible to implement some way to allow my de/serializer implementations to specify their own identify function?
Thanks,
Paul Wallace
When I will serialize an object that may contain nulls the serialization fails.
With version 1.4.0 everything works perfectly.
With version 1.5.0 I get the error that I show below.
example:
In Model:
...
@JsonProperty({name: 'resubmissionAfterDaysSelected'})
private _resubmissionAfterDaysSelected: number | null;
@JsonProperty({name: 'resubmissionAfterMessagesSelected'})
private _resubmissionAfterMessagesSelected: number | null;
...
Object values:
{
"_eventId": 2416,
"_version": 2,
"_eventStatusSelected": "Open",
"_userCommentCurrent": "",
"_falsePositiveSelected": false,
"_caseNoCurrent": "",
"_resubmissionAfterDaysSelected": null,
"_resubmissionAfterMessagesSelected": null
}
Execute:
ObjectMapper.serialize(object)
Error:
TypeError: can't convert null to object
Traza de la pila:
SerializeObjectType@http://localhost:4200/vendor.bundle.js:23906:22
thanks.
There seems to be a problem with deserializing floats:
class Test {
@JsonProperty({ name: 'test_test' }) test: number = 0.00;
}
const data = { test_test: '1.234' };
const testData: Test = ObjectMapper.deserialize(Test, data);
console.log(testData);
Outputs:
Test { test: "1.234" }
Hi, is this intended behavior?
class Example {
hello = null;
world = null;
}
const helloJson = []
const result = ObjectMapper.deserializeArray(Order, helloJson);
// expected []
// was undefined
console.log(result);
If not, it should be fixed. If so, it should be documented, as it seems like it could cause confusion.
Hi.
I have the following use case:
export class LoggedUserModel {
@JsonProperty({name: 'permissions', type: PermissionEnum
,deserializer: PermissionEnumDeserializer})
public permissions: PermissionEnum[];
}
The enum definition:
export enum PermissionEnum {
PERMISSION_EXAMPLE_1,
PERMISSION_EXAMPLE_2,
PERMISSION_EXAMPLE_3
}
@CacheKey('PermissionEnumDeserializer')
export class PermissionEnumDeserializer implements Deserializer {
deserialize = (value: string): PermissionEnum => return PermissionEnum[value] as PermissionEnum;
}
And the example of the Json:
{"permissions":["PERMISSION_EXAMPLE_1","PERMISSION_EXAMPLE_2"]}
The problem in this case is that deserialize method always receives whole values of the json, that is, deserialize is invoked twice with whole array values every time.
Hi !
If you deserialize a JSON inside an object, and then serialize it, array order are not keeped.
For example
{
"test": [1,2,3,4,5]
}
can become
{
"test": [2,1,5,4,3]
}
I think the problem comes from uniqueId()
inside SerializeArrayType
method.
Could you check it ?
Thanks
When you have a class with a null vale in some attribute, custom property name in serialization and deserialization processs not work, and json property name is ignored.
Examples are in TypeScript Syntax
Ex. User Domain Class
export class User {
@JsonProperty({name: "id"})
public _id: number;
@JsonProperty({name: "name"})
public _name: string;
@JsonIgnore()
public _password: string;
public constructor() {
this._id = null;
this._name = "Test User Name";
this._password = "gsa@aglaX!";
}
}
Ex. Serialization
let userInstance: User;
userInstance = ObjectMapper.serialize(singleTestDTO);
User instance: {"_id": null, "name": "Test User Name"}
If don't explicitly initialize _id to null, works, or if initialize to undefined, but no with null value...
It would be wonderful it worked with null values
Congratulations on working with module! ๐
Hi Team,
Please look at the below code segment from index.ts file. It's doing deserialisation twice per object because we are assigning the first element for deserialisation first and then the popped element again.
`const runDeserialization = (conversionFunctionStructures: ConversionFunctionStructure[]): void => {
const converstionFunctionsArray: Array<ConversionFunctionStructure> = [];
conversionFunctionStructures.forEach((struct: ConversionFunctionStructure) => {
converstionFunctionsArray.push(struct);
});
**let conversionFunctionStructure: ConversionFunctionStructure = converstionFunctionsArray[0];** //This line needs to be replaced with **let conversionFunctionStructure: ConversionFunctionStructure = (converstionFunctionsArray.length > 0)? converstionFunctionsArray.pop() : undefined;**
// tslint:disable-next-line:triple-equals
while (conversionFunctionStructure != undefined) {
const stackEntries: Array<ConversionFunctionStructure> = conversionFunctions[conversionFunctionStructure.functionName](
conversionFunctionStructure.instance, conversionFunctionStructure.instanceKey,
conversionFunctionStructure.type, conversionFunctionStructure.json,
conversionFunctionStructure.jsonKey);
stackEntries.forEach((structure: ConversionFunctionStructure) => {
converstionFunctionsArray.push(structure);
});
conversionFunctionStructure = converstionFunctionsArray.pop();
}
};`
Hello,
I'm currently writing an extension for Chrome and Firefox and I use json-object-mapper. My issue is that there is a bit of code that violates CSP (Content Security Policy).
Here is the error I get :
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".
The code that causes this error is const functionImpl = new Function(`return '${key}';`);
from src/main/DecoratorMetadata.ts:55
.
I tried adding 'unsafe-eval'
in the CSP as suggested by the error message, unfortunately, this CSP directive is forbidden in Firefox addons, and my extension got refused...
Is there any way you could fix json-object-mapper so that it doesn't trigger any CSP error please ?
Thanks in advance !
My setup is: Typescript with node on Serverless (AWS lambda). Whenever I call one of the lambda functions, I get the following:
Serverless: Error while loading lambdaFunc
[ '...\\node_modules\\json-object-mapper\\dist\\ObjectMapper.es2015.js:637',
'export { ObjectMapper, JsonProperty, JsonConverstionError, AccessType, CacheKey, JsonIgnore, DateSerializer };',
'SyntaxError: Unexpected token export',
The lambdaFunc file has the following:
import { ClassName1 } from "foo1";
import { ClassName2 } from "foo2";
import { ClassName3 } from "foo3";
and all those classes have:
import { JsonProperty } from "json-object-mapper";
this works fine. And then as soon as I add this to the lambdaFunc:
import { AnotherClass } from "foo4";
which has:
import { ObjectMapper } from "json-object-mapper";
I get the error above.
I'm pretty new to NodeJS and JS/TS development in general, and I'm lately facing this problem: when I try to compile and execute a little software of mine, the compilation terminates without any error whatsoever, while the execution throws the following error:
node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:637
export { ObjectMapper, JsonProperty, JsonConverstionError, AccessType, CacheKey, JsonIgnore, DateSerializer };
^^^^^^
SyntaxError: Unexpected token export
at createScript (vm.js:56:10)
at Object.runInThisContext (vm.js:97:10)
at Module._compile (module.js:542:28)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object.<anonymous>
My tsconfig.json is this one:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "build",
"sourceMap": true
},
"exclude": [
"node_modules"
],
"include": [
"src/**/*.ts"
]
}
Is something wroong with the package or am I missing something obvious?
Hello!
I ran into a problem today, when my production build was throwing misterious errors like t.map is not a function
. Spent some hours to localize an issue, then figured out that the reason was deserializers caching strategy, which doesn't work after minification. I've done some research and have read #2. @CacheKey
was the solution. I consider it strange, that the problem isn't mentioned in the documentation.
Thus, I wanted to suggest an improvement. The library could warn about missing @CacheKey
decorator, so developer would not occasionally shoot himself in the foot on production.
Does this framework still work for Angular 6?
Hello !
I have a problem when I want to deserialize an array. Here is my code:
@JsonProperty({name: 'myArray', required: false, type: Array<models.myVar>()}) public myArray: Array<models.myVar> = undefined;
This thrown an error like this when I use the ObjectMapper.deserialize method:
TypeError: metadata.type is not a constructor
at http://localhost:9876/_karma_webpack_/webpack:/D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:303:1
at Array.forEach ()
at Object.DeserializeComplexType D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:265:1)
at runDeserialization D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:612:1)
at Object.webpackJsonp.../../../../json-object-mapper/dist/ObjectMapper.es2015.js.ObjectMapper.deserialize
I've first modify my code like this:
@JsonProperty({name: 'myArray', required: false, type: Array<models.myVar>()}) public myArray: models.myVar[] = undefined;
But I've this other error:
TypeError: type is not a constructor
at Object.DeserializeArrayType D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:222:1)
at http://localhost:9876/_karma_webpack_/webpack:/D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:316:1
at Array.forEach ()
at Object.DeserializeComplexType D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:265:1)
at runDeserialization D:/projets/.../node_modules/json-object-mapper/dist/ObjectMapper.es2015.js:612:1)
at Object.webpackJsonp.../../../../json-object-mapper/dist/ObjectMapper.es2015.js.ObjectMapper.deserialize
I then modified the DeserializeArrayType method like this:
var typeInstance = new type();
to var typeInstance = type;
And it works now...
Can you tell me if there is a mistake in my or your code ? :)
Thanks a lot !
Marc
I am getting the following error:
Error: Cannot find module 'reflect-metadata'
Solution:
yarn add reflect-metadata
import "reflect-metadata";
Hi
I have found several "problems" related with the function deserialize
:
1. If you want to deserialize to a DTO, you should initialize all properties of the object. That is:
class SimpleRoster {
private name: String;
private worksOnWeekend: Boolean;
}
It doesn't work correctly, you should to include default values in all properties:
class SimpleRoster {
private name: String = undefined;
private worksOnWeekend: Boolean = undefined;
}
2. It is not possible to work with your "custom constructor":
export class InvoiceDetail {
constructor (private concept: string, private numberOfItems: number
,private cost: number) {}
}
export class Invoice {
constructor (private identifier: string, private month: number, private year: number
,private detail: InvoiceDetail[]) {}
}
Reading the definition of the ObjectMapper.deserialize
, this function only works with objects that have an "empty constructor" however, in this case, it implies that I should include "a lot of" boilerplate code.
Is there an option and/or way to deserialize a json string into objects of those classes (or similar classes) without to remove current constructors? (not always the "source" of those objects will be a Json string).
Thanks in advance
interface Result {
success: boolean;
message: string;
result: {} | {}[];
}
class ResultData implements Result {
// success: boolean;
// message: string;
// result: {} | {}[];
constructor(public success: boolean, public message: string, public result: {} | {}[]) {}
}
But I get a compile error because you expect a constructor() {}
to be available.
Argument of type 'typeof ResultData' is not assignable to parameter of type 'new () => ResultData'.
I guess one could argue that I don't need an interface for my data classes.
Mapping multiple JSON properties to one object property
For example I have the following JSON object:
obj = { id: '002', date: '05/07/1991', time:'22:35'
And I want to map it to the following class :
class Example { @JsonProperty() id = ''; datetime: Date = new Date(); }
I want to concatenate date and time to datetime. Ho would I go about acomplishing this?
Currently I have object that are nested 3-4 levels deep. However the library is currently only serializing 2 levels deep.
Is there an option somewhere to make the library deserialize deeper?
Hi
Sometimes it is necessary to include in the model (DTO in this case), several properties that you don't want to serialize and/or deserialize, so it would be nice add this functionality to this library.
Thanks in advance
Hi,
Awesome work here, pretty much similar to Java jakson library.
One quick question, at this point does this module supported on Node? . I think ES6 features being used here, so just want to check on this. Please share your thoughts
Hello,
Deserialization does not work on typescript 3.1.1 and/or Angular 10.
I copied, pasted and ran the SimpleRoster deserialization example on typescript 3.1.1 and/or Angular 10, but that example does not work.
I created stackblitz.
https://stackblitz.com/edit/angular-ivy-ftq9ct?file=src%2Fapp%2Fapp.component.ts
Is it possible to have a computed property or maybe multiple names/alias as part of the json mapper ?
Eg. Transformation
[{"id" : "someId"}, {"_id" : "sdfdf"}] => [{"id" : "someId"}, {"id" : "sdfdf"}]
Above I have 2 objects one with id
and another with _id
want to map both to id
in the resulting object
Also the cases file fullname = firstName + secondName
Hi,
I'm trying to use the json-object-mapper library in my Angular2 app. I have installed it via npm and my component is defined as below:
import { ObjectMapper } from 'json-object-mapper';
import { Item } from './../../models/item.model';
import { Component, OnInit,Inject } from '@angular/core';
@Component({
selector: 'app-results-content',
templateUrl: './results-content.component.html',
styleUrls: ['./results-content.component.css']
})
export class ResultsContentComponent implements OnInit {
constructor() { }
ngOnInit() {
let json = {
"Result": null,
"ResultId" : 2041,
"AnnotationText" : "hould",
"Confidence" : "0.4"
};
let testInstance: Item = ObjectMapper.deserialize(Item, json);
}
}
When I try to run the app, I keep getting an error like : "NoAnnotationError" Error: Cannot resolve all parameters for 'Parser'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Parser' is decorated with Injectable.
What can I do to resolve this?
My Item class is as below:
import {JsonProperty} from 'json-object-mapper';
export class Item {
@JsonProperty('Result')
result: string;
@JsonProperty('ResultId')
resultId: number;
@JsonProperty('AnnotationText')
annotationText: string;
@JsonProperty('Confidence')
confidence:string;
}
api = {
propy:"test",
array:[
{
atr:"hello"
},
{
atr:"hi"
}
]
}
deserialize = ObjectMapper.deserialize(MyClass, api)
console.log(deserialize);
returns =>
{
propy:"test",
array:[
{},
{}
]
}
It looks like it is not serializing getters.
The code below does not serialize the getter property.
export class ProjectModule extends ProjectBase {
@JsonProperty({ name: "t" })
public get ProjectType(): ProjectType {
return ProjectType.Module;
}
}
It only works with the code like this.
export class ProjectModule extends ProjectBase {
@JsonProperty({ name: "t" })
public readonly ProjectType: ProjectType = ProjectType.Module;
}
Any plan to implement getters and setters de/serialization?
I try deserialize my json-object like this
return this.http.get(url, { search: params }) .map(response => <Event[]>ObjectMapper.deserialize(Event[], response.json()));
but the follow error message has been thrown by webpack
You may need an appropriate loader to handle this file type.
| return this.http.get(url, { search: params })
| .map(function (response) { return json_object_mapper_1.ObjectMapper.deserialize(event_class_1.Event[], response.json()); });
| };
| return StageService;
Is it not possible, or what i doing wrong?
I am replicating the example class from the wiki page:
import {JsonProperty} from 'json-object-mapper';
export class SimpleRoster {
private worksOnWeekend: Boolean = undefined;
@JsonProperty({type: Date})
private systemDate: Date = undefined;
public isAvailableToday(): Boolean {
if (this.systemDate.getDay() % 6 === 0 && this.worksOnWeekend === false) {
return false;
}
return true;
}
}
but i get this:
.../node_modules\json-object-mapper\dist\ObjectMapper.es2015.js:1
(function (exports, require, module, __filename, __dirname) { import 'reflect-metadata';
is this the correct way?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.