hiranthaR / Json-to-Dart-Model

Json to Dart Model extension can convert JSON objects into Dart data classes. It supports pure Dart class conversion, Flutter-recommended JSON serialization using annotations, Freezed support, Effective Dart:Style, and many more features. Currently, it has more than 135,000 installs.
https://marketplace.visualstudio.com/items?itemName=hirantha.json-to-dart
MIT License
93 stars 17 forks source link

force key type #51

Closed Miamoto-Musashi closed 3 years ago

Miamoto-Musashi commented 3 years ago

would be nice to be able to force property type suppose we have:

{
"updated":{},
"created":{}
}

this will create 2 useless objects Updated and Created, would be nice instead to tell json2dart to create the corresponding properties in the class as Date objects

probably to follow the naming pattern can be:

{
"updated.date":{},
"created.date":{},
"issuer.user": {}
}
iamarnas commented 3 years ago

@Miamoto-Musashi Hi 👋

Here are all supported date formats.

2008-09-15T15:53:00
2007-03-01T13:00:00Z
2015-10-05T21:46:54-1500
2015-10-05T21:46:54+07:00
2020-02-06T14:00:00+00:00

To tell that you want a date object just copy and paste one of the formats and the generator will detect it.

{
  "updated": "2008-09-15T15:53:00",
  "created": "2008-09-15T15:53:00"
}

Or your mean to speed up the coding by adding the date keyword?

Miamoto-Musashi commented 3 years ago

@iamarnas thx for clarifying, is it documented the date feature? my request BTW is not only for dates but for every type like User: ("issuer.user": {})

iamarnas commented 3 years ago

@Miamoto-Musashi Can you provide me an exact example with raw JSON and final Dart code?

@iamarnas thx for clarifying, is documented the date feature?

No 😄 But I can add this, np.

Miamoto-Musashi commented 3 years ago

Hi @iamarnas

 //   REQUEST
  {
    "__className": "Request.model",
    "key": "5621f8a9-f05a-4469-bddf-0cdb56b24771-3",
    "candidates.candidate": [{}], <-- type Candidate
    "cargoes.cargo": [{}], <-- type Cargo
    "cargoSummary.summary": <-- type Summary
    "loadContacts.contact": [{ <--type Contact
      // "__className": "Contact.model",
      "key": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "address": null,
      "phone": "+393477972533",
      "organizationKey": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "countryCode": "ITA",
      "lastUpdate": "2015-10-05T21:46:54+07:00", //UTC time, need to be converted from and to FrontEnd
      "r@isOrigin": true
    }], //minutes
    "unLoadContacts.contact": [{
      "key": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "address.address": null, <--type Address
      "phone": "+393477972533",
      "organizationKey": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "countryCode": "ITA",
      "lastUpdate": "2015-10-05T21:46:54+07:00", //UTC time, need to be converted from and to FrontEnd
      "r@isOrigin": true
    }], 
  },

// CANDIDATE
  {
    "__className": "Candidate.model",
    "distance":{
      "lastUpdate": "2015-10-05T21:46:54+07:00",  
    },
    "motorKey":"110afe06-ec31-4d9b-b933-d9e060c7bcb7"
  },

.....

would generate something similar to:


// assuming everything on the same folder by  #45  
import 'candidate.model.dart'; 
import 'cargo.model.dart'; 
import 'summary.model.dart'; 

class Request {
  String key;
  List<Candidate> candidates;
  List<Cargo> cargoes;
  Summary cargoSummary;
  List<Contact> loadContacts;
  List<Contact> unLoadContacts;
....
}

somewhere else we defined the Cargo, Candidate objects

iamarnas commented 3 years ago

@Miamoto-Musashi Would look like this with enhancement.

  {
    "__className": "Request.model",
    "key": "5621f8a9-f05a-4469-bddf-0cdb56b24771-3",
    "candidates.candidate": [{}], <-- type Candidate
    "cargoes.cargo": [{}], <-- type Cargo // If you want to have cargo in the same directory, then you need to provide an object. Otherwise will be created an empty class.
    "cargoSummary.summary": <-- type Summary
    "loadContacts.contact": [{ <--type Contact
      // "__className": "Contact.model", <- This only works for main json objects as base class name.
      // Class name takes from the list object's json key. In this case would be `Concat`with echancement.
      "key": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "address": null,
      "phone": "+393477972533",
      "organizationKey": "110afe06-ec31-4d9b-b933-d9e060c7bcb7",
      "countryCode": "ITA",
      "lastUpdate": "2015-10-05T21:46:54+07:00",
      "r@isOrigin": true
    }], 
    "unLoadContacts.contact": [{}], // <- For duplicates don't need provide object would create from the first object.
  },

It can be fixed but you would need to manually handle your empty objects. It is not possible to provide results without any parameters.

Miamoto-Musashi commented 3 years ago

the objects wouldn't be empty by my example in jsonc file you can find in the root the definition of the Candidate object when generated everything would be consistent; yes is an enhancement

iamarnas commented 3 years ago

the objects wouldn't be empty by my example in jsonc file you can find in the root the definition of the Candidate object when generated everything would be consistent; yes is an enhancement

@Miamoto-Musashi A question. What wrong if you put Candidate directly to the list, why you need it separated, when you can initialize it directly?

Miamoto-Musashi commented 3 years ago

@iamarnas I need it to be separated cause is referenced in other json but with smaller attribute set, what I do today is to generate it from the root with __className, move all dart models mv lib/commons/models/**/*.dart lib/commons/models, put null in all other references and adjust at the end with a find in files command. If I don't put it in the root other copies of the class will overwrite the complete one.

iamarnas commented 3 years ago

@Miamoto-Musashi HI :wave: Can you try and test forcing key types. It's supported in the last version. And as a bonus, you can test the override path in the models.jsonc. You can navigate your object as you want and where you want.

Example:

{
    "__className": "Candidate.model",
    "__path": "/lib/models/candidate", // <- override default path with a new one by adding '__path' key
    "distance":{
      "lastUpdate": "2015-10-05T21:46:54+07:00",  
    },
    "motorKey":"110afe06-ec31-4d9b-b933-d9e060c7bcb7"
}

any suggestions on how to improve it are welcome :smiley:

Miamoto-Musashi commented 3 years ago

on a first run seems working fine, thank you. will make some more test on this week and let you know

Miamoto-Musashi commented 3 years ago

Hi @iamarnas I found a bug:

I have this jsonc

{
...
    "trailers": [
      {
        "key": "Trailer",
        "dimension": null,
        "type.trailertype": {}
      }
    ],
},

//EQUIPMENT
  {
    "__className": "Equipment.model",
//....
    "type.trailertype": {}
  }, 
 //TRAILERTYPE
  {
    "__className": "TrailerType.model",
    "key": "key",
    "r@type": "string",
    "code":"string"
  },

the trailer type model on the root is generated correctly with the underscore and camel case perfectly balanced (only style warning sort constructors before other members)

class TrailerType {
  String key;
  String type;
  String code;

  TrailerType({this.key, @required this.type, this.code});

  factory TrailerType.fromJson(Map<String, dynamic> json) => TrailerType(
        key: json['key'] as String,
        type: json['type'] as String,
        code: json['code'] as String,
      );

  Map<String, dynamic> toJson() => {
        'key': key,
        'type': type,
        'code': code,
      };
}

but the trailer type in equipment is generated with wrong name in file and in class: file name should be trailer_type.dart but is trailertype.dart; class is the following

import 'trailertype.model.dart'; <-- should be `import trailer_type.model.dart`

class Equipment {
  String key;
  String name;
  String organizationKey;
  Trailertype type; <-- should be TrailerType

  Equipment({this.key, this.name, this.organizationKey, this.type});

  factory Equipment.fromJson(Map<String, dynamic> json) => Equipment(
        key: json['key'] as String,
        name: json['name'] as String,
        organizationKey: json['organizationKey'] as String,
        type: json['type'] == null
            ? null
            : Trailertype.fromJson(json['type'] as Map<String, dynamic>),
      );

  Map<String, dynamic> toJson() => {
        'key': key,
        'name': name,
        'organizationKey': organizationKey,
        'type': type?.toJson(),
      };
}
iamarnas commented 3 years ago

@Miamoto-Musashi Thanks for this reporting. I will fix it fast as possible.

iamarnas commented 3 years ago

@Miamoto-Musashi I found the problem. The problem is in your code, to tell the generator where you want uppercase you need separate words by uppercase or dash. Otherwise, the generator takes it as a word.

Example:

 {
    "key": "Trailer",
    "dimension": null,
    "type.trailertype": {} // <- should be "type.trailerType" or "type.trailer_type"
}

I would you recommend to follow some principles. Example: for all JSON keys use the dash to separate words user_id it will be generated in all ways userId as everywhere in your examples. It will be more secure to avoid mistakes. It is just different with user_id vs userId, that json_serializable or Freezed will not add JSON key annotation by using userId.

only style warning sort constructors before other members.

Do you know that you can enable in the settings sort constructors first?

iamarnas commented 3 years ago

I'm closing it because no see issues with it at the moment. Open the new issues report if you have some problem that relates to this.