Immutable value types, enum classes, and serialization.

Overview

Built Values for Dart

Build Status

Introduction

Built Value provides:

  • Immutable value types;
  • EnumClass, classes that behave like enums;
  • JSON serialization.

Immutable collections are from built_collection.

See the API docs.

Articles

Tutorials

Tools

Examples

For an end to end example see the chat example, which was demoed at the Dart Summit 2016. The data model, used both client and server side, uses value types, enums and serialization from built_value.

Simple examples are here.

Since v5.2.0 codegen is triggered by running pub run build_runner build to do a one-off build or pub run build_runner watch to continuously watch your source and update the generated output when it changes. Note that you need a dev dependency on built_value_generator and build_runner. See the example pubspec.yaml.

If using Flutter, the equivalent command is flutter packages pub run build_runner build. Alternatively, put your built_value classes in a separate Dart package with no dependency on Flutter. You can then use built_value as normal.

If using a version before v5.2.0, codegen is triggered via either a build.dart to do a one-off build or a watch.dart to continuously watch your source and update generated output.

Value Types

Value types are, for our purposes, classes that are considered interchangeable if their fields have the same values.

Common examples include Date, Money and Url. Most code introduces its own value types. For example, every web app probably has some version of Account and User.

Value types are very commonly sent by RPC and/or stored for later retrieval.

The problems that led to the creation of the Built Value library have been discussed at great length in the context of AutoValue for Java.

In short: creating and maintaining value types by hand requires a lot of boilerplate. It's boring to write, and if you make a mistake, you very likely create a bug that's hard to track down.

Any solution for value types needs to allow them to participate in object oriented design. Date, for example, is the right place for code that does simple date manipulation.

AutoValue solves the problem for Java with code generation, and Built Values does the same for Dart. The boilerplate is generated for you, leaving you to specify which fields you need and to add code for the behaviour of the class.

Generating boilerplate for Value Types

Value types require a bit of boilerplate in order to connect it to generated code. Luckily, even this bit of boilerplate can be got automated using code snippets support in your favourite text editor. For example, in IntelliJ you can use following live template:

abstract class $CLASS_NAME$ implements Built<$CLASS_NAME$, $CLASS_NAME$Builder> {
  $CLASS_NAME$._();
  factory $CLASS_NAME$([void Function($CLASS_NAME$Builder) updates]) = _$$$CLASS_NAME$;
}

Using this template you would only have to manually enter a name of your data class name which is something that can't be automated.

Enum Class

Enum Classes provide classes with enum features.

Enums are very helpful in modelling the real world: whenever there are a small fixed set of options, an enum is a natural choice. For an object oriented design, though, enums need to be classes. Dart falls short here, so Enum Classes provide what's missing!

Design:

  • Constants have name and toString, can be used in switch statements, and are real classes that can hold code and implement interfaces
  • Generated values method that returns all the enum values in a BuiltSet (immutable set)
  • Generated valueOf method that takes a String

Serialization

Built Values comes with JSON serialization support which allows you to serialize a complete data model of Built Values, Enum Classes and Built Collections. The chat example shows how easy this makes building a full application with Dart on the server and client.

Here are the major features of the serialization support:

It fully supports object oriented design: any object model that you can design can be serialized, including full use of generics and interfaces. Some other libraries require concrete types or do not fully support generics.

It allows different object oriented models over the same data. For example, in a client server application, it's likely that the client and server want different functionality from their data model. So, they are allowed to have different classes that map to the same data. Most other libraries enforce a 1:1 mapping between classes and types on the wire.

It requires well behaved types. They must be immutable, can use interface but not concrete inheritance, must have predictable nullability, hashCode, equals and toString. In fact, they must be Enum Classes, Built Collections or Built Values. Some other libraries allow badly behaved types to be serialized.

It supports changes to the data model. Optional fields can be added or removed, and fields can be switched from optional to required, allowing your data model to evolve without breaking compatbility. Some other libraries break compatibility on any change to any serializable class.

It's modular. Each endpoint can choose which classes to know about; for example, you can have multiple clients that each know about only a subset of the classes the server knows. Most other libraries are monolithic, requiring all endpoints to know all types.

It has first class support for validation via Built Values. An important part of a powerful data model is ensuring it's valid, so classes can make guarantees about what they can do. Other libraries also support validation but usually in a less prominent way.

It's pluggable. You can add serializers for your own types, and you can add plugins which run before and after all serializers. This could be used to interoperate with other tools or to add hand coded high performance serializers for specific classes. Some other libraries are not so extensible.

It was designed to be multi language, mapping to equivalent object models in Java and other languages. Currently only Dart is supported. The need for other languages didn't materialize as servers are typically either written in Dart or owned by third parties. Please open an issue if you'd like to explore support in more languages.

Common Usage

While full, compiled examples are available in example/lib, a common usage example is shown here. This example assumes that you are writing a client for a JSON API representing a person that looks like the following:

{
  "id": 12345,
  "age": 35,
  "first_name": "Jimmy",
  "hobbies": ["jumping", "basketball"]
}

The corresponding dart class employing built_value might look like this. Note that it is using the @nullable annotation to indicate that the field does not have to be present on the response, as well as the @BuiltValueField annotation to map between the property name on the response and the name of the member variable in the Person class.

import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:built_collection/built_collection.dart';

part 'person.g.dart';

abstract class Person implements Built<Person, PersonBuilder> {
  static Serializer<Person> get serializer => _$personSerializer;

  // Can never be null.
  int get id;

  @nullable
  int get age;

  @nullable
  @BuiltValueField(wireName: 'first_name')
  String get firstName;

  @nullable
  BuiltList<String> get hobbies;

  Person._();
  factory Person([void Function(PersonBuilder) updates]) = _$Person;
}

FAQ

How do I check a field is valid on instantiation?

The value class private constructor runs when all fields are initialized and can do arbitrary checks:

abstract class MyValue {
  MyValue._() {
    if (field < 0) {
      throw ArgumentError(field, 'field', 'Must not be negative.');
    }
  }

How do I process a field on instantiation?

Add a hook that runs immediately before a builder is built. For example, you could sort a list, so it's always sorted directly before the value is created:

abstract class MyValue {
  @BuiltValueHook(finalizeBuilder: true)
  static void _sortItems(MyValueBuilder b) =>
      b..items.sort();

How do I set a default for a field?

Add a hook that runs whenever a builder is created:

abstract class MyValue {
  @BuiltValueHook(initializeBuilder: true)
  static void _setDefaults(MyValueBuilder b) =>
      b
        ..name = 'defaultName'
        ..count = 0;

Should I check in and/or publish in the generated .g.dart files?

See the build_runner docs. You usually should not check in generated files, but you do need to publish them.

Features and bugs

Please file feature requests and bugs at the issue tracker.

Comments
  • firestore timestamp to datetime serializer

    firestore timestamp to datetime serializer

    I don't know if I should create it as an issue or not. Firestore is changing its behaviour for storing datetime type data. Firestore has its own type Timestamp to store datetime data. We usually don't want to tightly couple our entities with data type from a specific vendor and want to represent date time data with language native data type which is DateTime in dart. I wrote a serializer plugin to convert Timestamp to DateTime. Thought I should share it, might be helpful for someone.

    import 'package:built_value/serializer.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    
    class TimestampSerializerPlugin implements SerializerPlugin {
      @override
      Object beforeSerialize(Object object, FullType specifiedType) {
        if (object is DateTime && specifiedType.root == DateTime)
          return object.toUtc();
        return object;
      }
    
      @override
      Object afterSerialize(Object object, FullType specifiedType) {
       if (specifiedType.root == DateTime)
          return Timestamp.fromMicrosecondsSinceEpoch(object); 
       return object;
      }
    
      @override
      Object beforeDeserialize(Object object, FullType specifiedType) {
        if (object is Timestamp && specifiedType.root == DateTime) {
          return object.microsecondsSinceEpoch;
          // return object.toDate();
        } else {
          return object;
        }
      }
    
      @override
      Object afterDeserialize(Object object, FullType specifiedType) {
        return object;
      }
    }
    

    and then you can add it like StandardJsonPlugin.

    final Serializers serializers = (_$serializers.toBuilder()
          ..add(GeoPointSerializer())
          ..addPlugin(new StandardJsonPlugin())
          ..addPlugin(new TimestampSerializerPlugin()))
        .build();
    
    p2 / feature request 
    opened by neerajyadav 40
  • how to deserialize

    how to deserialize

    I find it hard to find information about how to deserialize

    I'd expect something like

        final accJson = JSON.decode("""
    {
        "profileId": 1,
        "emailAddress": "[email protected]",
        "dob": "1984-02-05",
        "premium": false,
        "membershipId": null,
        "adverts": true,
        "homeLatitude": 53.7966667,
        "homeLongitude": -1.5340407,
        "latitude": 53.7939665,
        "longitude": -1.5393381,
        "keyValues": {
            "gender": "male"
        }
    }
    """) as Map<String, dynamic>;
    
    final acc = Account.deserialize(accJson)
    

    but that doesn't work

    ERROR: The method 'deserialize' isn't defined for the class 'Serializer<Account>'. ([myproj] test/models.dart:31)
    
    opened by zoechi 31
  • Issue with analyzer 0.40.5, InconsistentAnalysisException

    Issue with analyzer 0.40.5, InconsistentAnalysisException

    I haven't dug into this more deeply, but in attempting to run with bleeding edge 2.12 and analyzer 0.40.5 I encountered the following error building one of our packages. It may be something that's going to be an issue in upcoming builds.

    [SEVERE] built_value_generator:built_value on lib/src/data/models/attachment.sg.dart: Error in BuiltValueGenerator for abstract class Attachment implements Built<Attachment*, dynamic>*. InconsistentAnalysisException: Requested result might be inconsistent with previously returned results

    p2 / bug 
    opened by alanknight-wk 30
  • Flutter Color as field failed generation

    Flutter Color as field failed generation

    Using Color get color; error to

    import 'package:built_value/built_value.dart';
    import 'dart:ui';
    
    part 'myclass.data.g.dart';
    
    abstract class MyClass implements Built<MyClass, MyClassBuilder> {
    
      String get name;
      bool get completed;
      Color get color;
    
      @nullable
      String get description;
    
      MyClass._();
    
      factory MyClass([updates(MyClassBuilder b)]) = _$MyClass;
    }
    

    ` Please make the following changes to use BuiltValue:

    1. Make field color have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported. [`

    I've try using dart:ui or flutter/material as import, Type is recognised by the IDE but not when using built_value. Not sure what I missed.

    Thank you.

    opened by Solido 25
  • Add serializer plugin that does renames

    Add serializer plugin that does renames

    That is one of requirements, that probably appears only when one works with external API. In my case models have many String fields that can have values only from some predefined list: For example, the field chartType can have values

    • table
    • barchart
    • linechart
    • pivot-table

    and so on. Ideally, I would like to use Enums for such fields, but some of the possible values (pivot-table in above example) are not valid dart identifiers.

    It would be great If we could change serialized value of Enum by some annotation.

    For example, given enum

    
    class SecondTestEnum extends EnumClass {
      static const SecondTestEnum yes = _$ys;
      static const SecondTestEnum no = _$n;
      static const SecondTestEnum definitely = _$definitely;
      @SerializedAs('no-thanks')
      static const SecondTestEnum noThanks = _$noThanks;
      const SecondTestEnum._(String name) : super(name);
      static Serializer<SecondTestEnum> get serializer => _$secondTestEnumSerializer;
      static BuiltSet<SecondTestEnum> get values => _$vls;
      static SecondTestEnum valueOf(String name) => _$vlOf(name);
    }
    
    

    Its implementation would be:

    const SecondTestEnum _$ys = const SecondTestEnum._('yes');
    const SecondTestEnum _$n = const SecondTestEnum._('no');
    const SecondTestEnum _$definitely = const SecondTestEnum._('definitely');
    const SecondTestEnum _$noThanks = const SecondTestEnum._('no-thanks');
    
    SecondTestEnum _$vlOf(String name) {
      switch (name) {
        case 'yes':
          return _$ys;
        case 'no':
          return _$n;
        case 'definitely':
          return _$definitely;
        case 'no-thanks':
          return _$noThanks;
        default:
          throw new ArgumentError(name);
      }
    }
    
    ...
    
    p2 / feature request 
    opened by vadimtsushko 24
  • Support chunked serialization / deserialization

    Support chunked serialization / deserialization

    Even though the generated serialization / deserialization logic may be very fast, on larger payloads it may hog the thread enough to cause missed frames on flutter. It'd be nice if there was an API to asynchronously decode a JSON response, and somehow intelligently split itself up over multiple smaller future callbacks, before returning the result.

    p3 / feature request 
    opened by ScottPierce 24
  • generated serializer is not a subtype of Serializer<...>

    generated serializer is not a subtype of Serializer<...>

    I have following model

    abstract class Pagination<T>
        implements Built<Pagination<T>, PaginationBuilder<T>> {
      static Serializer<Pagination> get serializer => _$paginationSerializer;
    
      factory Pagination([void Function(PaginationBuilder<T>) updates]) =
          _$Pagination<T>;
    
      Pagination._();
    
      int get count;
      String get next;
      String get previous;
      BuiltList<T> get result;
    
      String toJson() {
        return json.encode(serializers.serializeWith(Pagination.serializer, this));
      }
    
      static Pagination fromJson(String jsonString) {
        return serializers.deserializeWith(
          Pagination.serializer,
          json.decode(jsonString),
        );
      }
    }
    
    

    when I try to deserialize json with it I get following error

    Unhandled Exception: type '_$PaginationSerializer' is not a subtype of type Serializer<Pagination<Product>>'
    

    not really sure why this is happening

    built_collection 4.3.2 built_value 7.1.0 built_value_generator 7.1.0 any hints is appreciated

    question 
    opened by krevedkokun 21
  • Custom Discriminator Function

    Custom Discriminator Function

    I have a rather annoying complex data model that I'm trying to map out with built_value. It's a weird case of Polymorphism where an object contains a list of mixed types. These mixed types (like the animal case) are polymorphic, but I don't know which type it should be until I look at an enum type variable on the object. I see there's the concept of the discriminator field which can be used to determine which serializer to use, but I'm not sure that's quite enough in my situation. It'd be nice to take something like a function to switch on the EnumClass (non nullable) and determine what serializer to use for each object in the list.

    Dashboard {
      tiles: [ {type: "TYPE1", ...}, {type: "TYPE2", ...} ],
      ...
    }
    

    It would be interesting to be able to define this function on the generated class that extends Built.

    Here's what I have so far, but I think it fails because it doesn't know which type of Tile to instantiate when it deserializes a Dashboard.

    abstract class Dashboard implements Built<Dashboard, DashboardBuilder> {
      static Serializer<Dashboard> get serializer => _$dashboardSerializer;
    
      int get entity;
      int get id;
      String get name;
      bool get defaultRoomDashboard;
      bool get external;
      String get publicUrlKey;
      bool get subscriptionRequired;
      int get container;
      String get containerName;
      BuiltSet<Tile> get tiles;
    
      factory Dashboard([updates(DashboardBuilder b)]) = _$Dashboard;
      Dashboard._();
    }
    
    @BuiltValue(instantiable: false)
    abstract class Tile<T> extends Object with TileViewMixin<T> implements Built<Tile<T>, TileBuilder<T>> {
      int get id;
      TileType get type;
      int get dashboard;
      int get order;
      bool get expanded;
      @override
      T get view;
    }
    
    abstract class SavedViewTile extends Object with TileViewMixin<SavedView> implements Built<SavedViewTile, SavedViewTileBuilder> {
      static Serializer<SavedViewTile> get serializer => _$savedViewTileSerializer;
    
      @override
      SavedView get view;
    
      factory SavedViewTile([updates(SavedViewTileBuilder b)]) = _$SavedViewTile;
      SavedViewTile._();
    }
    
    abstract class WidgetTile extends Object with TileViewMixin<WidgetView> implements Built<WidgetTile, WidgetTileBuilder> {
      static Serializer<WidgetTile> get serializer => _$widgetTileSerializer;
    
      @override
      WidgetView get view;
    
      factory WidgetTile([udpates(WidgetTileBuilder b)]) = _$WidgetTile;
      WidgetTile._();
    }
    
    abstract class RoomNoteTile extends Object with TileViewMixin<RoomNoteView> implements Built<RoomNoteTile, RoomNoteTileBuilder> {
      static Serializer<RoomNoteTile> get serializer => _$roomNoteTileSerializer;
    
      @override
      RoomNoteView get view;
    
      factory RoomNoteTile([udpates(RoomNoteTileBuilder b)]) = _$RoomNoteTile;
      RoomNoteTile._();
    }
    
    abstract class TileViewMixin<T> {
      T get view;
    }
    

    With my suggested feature improvement you could have something like this for the Tile class.

    @BuiltValue(instantiable: false)
    abstract class Tile<T> extends Object with TileViewMixin<T> implements Built<Tile<T>, TileBuilder<T>> {
      int get id;
      TileType get type;
      int get dashboard;
      int get order;
      bool get expanded;
      @override
      T get view;
    
      Serializer get discriminator {
        switch (type) {
          case TileType.SAVED_VIEW:
            return SavedViewTile.serializer;
          case TileType.ROOM_NOTE:
            return RoomNoteTile.serializer;
        }
      }
    }
    

    Unless I'm missing something... Furthermore, if this would be better for SO just let me know and I can move it there.

    p3 / feature request 
    opened by jpgilchrist 18
  • Allow custom toString, hashCode, equals

    Allow custom toString, hashCode, equals

    It looks like toString() is overridden by default. I'd like to have the option to provide my own toString(), and have built_value provide it only when it's not explicitly defined on the abstract class.

    The strings generated by built_value contain a lot of newlines and get messy, especially when logging (the number one reason to call toString for me).

    p2 / feature request 
    opened by filiph 17
  • Need way to subscribe to built instance changes

    Need way to subscribe to built instance changes

    Issue

    When writing angular components, typically we want to take as @Input an immutable built value instance, and as @Output we want to push new immutable built value instances with any modifications. This is ideal for developer UX because the angular component does not share references to any mutable data structures.

    Doing this with built value is awkward because we have no way to subscribe to changes to a built value builder instance. For a form component, for every field modified in the form, we have to write a method in the angular component that updates the input and adds the new model to the output stream. If there are 10 inputs in the form, that's 10 methods that are almost the same. You can share the common pieces of these methods, but it's still repetitive and adds a lot of methods to the component.

    Example

    @Component(
      selector: 'some-form',
      template: '''
      <input [ngModel]="thing.a" (ngModelChange)="changeA(\$event)">
      <input [ngModel]="thing.b" (ngModelChange)="changeB(\$event)">
    '''
    )
    class SomeForm {
      @Input()
      BuiltThing thing;
    
      @Output()
      Stream<BuiltThing> thingChange;
    
      void changeA(Object value) => thingChange.add(thing.rebuild((b) => b..a = value)));
      void changeB(Object value) => thingChange.add(thing.rebuild((b) => b..b = value)));
    }
    

    Suggested fix 1

    Optionally generate an additional class that is immutable, called ThingRebuilder, that exposes a Stream<ThingRebuilder> onChange and a setter for each field which outputs modified ThingRebuilders to the stream. This class can have its properties 2 way bound to the inputs.

    Suggested fix 2

    Add a Stream<void> change listener to the generated builder. That stream is triggered after any setter is called on the builder. This makes it so we can use a builder instance internally in the component and output to the stream the result of thingBuilder.build() whenever the builder is modified.

    p2 / feature request 
    opened by moodysalem 16
  • Generate copyWith method

    Generate copyWith method

    Hi,

    in cases where you would like to update only certain fields of an object it makes sense to declare a copyWith method which creates a new object with the passed object's fields (if not null) or (otherwise) the original object's fields as such:

    abstract class UserState implements Built<UserState, UserStateBuilder> {
    
      @nullable
      Auth get auth;
    
      @nullable
      String get name;
    
      @nullable
      BuiltMap<int, Friend> get friends;
    
      UserState._();
    
      factory UserState([updates(UserStateBuilder b)]) = _$UserState;
    
      UserState copyWith(UserState updates) {
        return UserState((b) => b
          ..name = updates.name ?? name
          ..friends.replace(updates.friends ?? friends)
          ..auth.replace(updates.auth ?? auth));
      }
    }
    

    This code is pretty much the same for each model class I have, just the field names change. Is there any possibility to make built_value generate the copyWith implementations or is there already some similar functionality? I did not find any docs or examples for this so I assume there is currently no such functionality, please point me in the right direction if I overlooked something.

    If that's not the case: Is this feature in the scope of built_value? Are there any plans to implement this feature?

    p2 / feature request 
    opened by giorgiogross 16
  • Failed to precompile build script .dart_tool/build/entrypoint/build.dart

    Failed to precompile build script .dart_tool/build/entrypoint/build.dart

    flutter pub run build_runner build --delete-conflicting-outputs I ran the above cmd to generate .g file 1 months ago, but now it reporting this error message. Try to do flutter clean and pub get again, but it doesn't resolve the issue.

    Can anyone help me to fix this issue?

    Thanks

    `[INFO] Generating build script completed, took 351ms [WARNING] /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/serializer_source_library.dart:125:43: Error: The getter 'element' isn't defined for the class 'DartType'.

    • 'DartType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. SerializerSourceClass(type!.element as InterfaceElement))); ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/dart_types.dart:26:31: Error: The getter 'element' isn't defined for the class 'DartType'.
    • 'DartType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. ValueSourceClass(type.element as ClassElement).settings.instantiable; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/dart_types.dart:31:12: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. type.element.allSupertypes ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/dart_types.dart:75:25: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. return dartType.element.name + suffix; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/dart_types.dart:80:28: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. return '${dartType.element.name}<$typeArgumentsStr>$suffix'; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/dart_types.dart:83:23: Error: The getter 'element' isn't defined for the class 'TypeParameterType'.
    • 'TypeParameterType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. return dartType.element.name + suffix; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:78:45: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .any((interfaceType) => interfaceType.element.name == 'Built'); ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:96:29: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. ...element.supertype!.element.allSupertypes ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:219:49: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .where((interfaceType) => interfaceType.element.name == 'Builder') ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:319:57: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .where((interface) => needsBuiltValue(interface.element)) ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:328:55: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .where((interface) => needsBuiltValue(interface.element)) ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:367:24: Error: The getter 'enclosingElement' isn't defined for the class 'MethodElement'.
    • 'MethodElement' is from 'package:analyzer/dart/element/element.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/element.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'enclosingElement'. var clazz = method.enclosingElement; ^^^^^^^^^^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:379:50: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. (interfaceType) => interfaceType.element.name == 'Built') || ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/value_source_class.dart:1080:48: Error: The getter 'element' isn't defined for the class 'DartType'.
    • 'DartType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. field.element.getter!.returnType.element!.displayName; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/serializer_source_class.dart:146:31: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .map((type) => type.element.name) ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/serializer_source_class.dart:155:31: Error: The getter 'element' isn't defined for the class 'InterfaceType'.
    • 'InterfaceType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. .map((type) => type.element.name) ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/serializer_source_class.dart:196:42: Error: The getter 'element' isn't defined for the class 'DartType'.
    • 'DartType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. final fieldTypeElement = fieldType.element; ^^^^^^^ /Users/calvin/.pub-cache/hosted/pub.dartlang.org/built_value_generator-8.4.2/lib/src/serializer_source_class.dart:205:36: Error: The getter 'element' isn't defined for the class 'DartType'.
    • 'DartType' is from 'package:analyzer/dart/element/type.dart' ('/Users/calvin/.pub-cache/hosted/pub.dartlang.org/analyzer-5.1.0/lib/dart/element/type.dart'). Try correcting the name to the name of an existing getter, or defining a getter or field named 'element'. final typeElement = type.element; ^^^^^^^ [INFO] Precompiling build script... completed, took 809ms [SEVERE] Failed to precompile build script .dart_tool/build/entrypoint/build.dart. This is likely caused by a misconfigured builder definition.`
    opened by celvinren 0
  • Add `non_constant_identifier_names` to ignore rule set

    Add `non_constant_identifier_names` to ignore rule set

    In certain cases, a non_constant_identifier_name lint can be triggered by the generator.

    For example, consider the following declaration:

    @SerializersFor([
      ...
    ])
    final Serializers _serializers = _$_serializers;
    

    The _serializers variable is meant to be private to the built_value type's file, however the resultant _$_serializers variable fails the non_constant_identifier_names lint causing pana errors when publishing.

    opened by dnys1 0
  • Bump actions/checkout from 3.1.0 to 3.2.0

    Bump actions/checkout from 3.1.0 to 3.2.0

    Bumps actions/checkout from 3.1.0 to 3.2.0.

    Release notes

    Sourced from actions/checkout's releases.

    v3.2.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/checkout/compare/v3...v3.2.0

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Drop dependency on quiver

    Drop dependency on quiver

    The package had been used for only two utilities, concat and zip.

    Replace zip with IterableZip from package:collection which is also an existing dependency.

    Replace concat with either ... elements in a list literal (since the collections are always iterated anyway) or by replacing .map with .expand.

    opened by natebosch 4
  • Built Class with too many fields causes code generation to fail due to too much nesting in generated hashCode

    Built Class with too many fields causes code generation to fail due to too much nesting in generated hashCode

    built_value_generator fails when trying to generate code for a class that has too many (several hundred) fields.

    Repro: https://gist.github.com/knaeckeKami/4ea80b2c078abcf8717a6aa59b3aea9b

    The output of running build_runner contains this error message:

    [SEVERE] built_value_generator:built_value on lib/built_value_limits.dart:
    An error `FormatterException` occurred while formatting the generated source for
      `package:built_value_limits/built_value_limits.dart`
    which was output to
      `lib/built_value_limits.built_value.g.part`.
    This may indicate an issue in the generator, the input source code, or in the
    source formatter.
    Could not format because the source could not be parsed:
    
    line 3003, column 2001 of .: The file has too many nested expressions or statements.
         ╷
    3003 │ $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc [...]
    

    The issue is that the generated hashCode method combines the hashCode of all fields in a single nested expression and, when there are too many fields, this seems to break the dart formatter.

    Also, I tested with built classes that have many fields (like 100), but not enough to break the dart formatter; It seems that even these classes cause the dart formatter to slow down a lot, and this nested hashcode expression seems to play a role in that.

    I created an example project with one single built_value class with 100 fields (similar to the repo above, but with only 100 instead of 1000 fields so that code generation still works) and measured the performance of dart format . with nested hashCode and with a version that does not nest the $jc() calls.

    Here are the outputs:

    Nested version (current implementation of built_value_generator)

    ➜  dart format .
    Formatted 4 files (0 changed) in 3.43 seconds.
    ➜  dart format .
    Formatted 4 files (0 changed) in 3.39 seconds.
    ➜  dart format .
    Formatted 4 files (0 changed) in 3.48 seconds.
    

    flat version:

    dart format .
    Formatted 4 files (0 changed) in 2.74 seconds.
    ➜  dart format .
    Formatted 4 files (0 changed) in 2.60 seconds.
    ➜  dart format.
    Formatted 4 files (0 changed) in 2.67 seconds.
    

    It seems the flat version is more friendly for the dart formatter as it will cause the source code to be formatted faster. I think the amount of fields that start to cause issues is around 20, since this is the amount of fields that the dart formatter can format in its preferred style without going over to 80 characters limit. (I did not measure the exact point where dart format becomes noticeably slower though, it's just a guess).

    The flat version would construct the hashCode like this

        int hash = 0;
        hash = $jc(hash, value0.hashCode);
        hash = $jc(hash, value1.hashCode);
        hash = $jc(hash, value2.hashCode);
        hash = $jc(hash, value3.hashCode);
        hash = $jc(hash, value4.hashCode);
    

    instead of this:

    ($jc($jc($jc($jc(0, value0.hashCode), value1.hashCode), value2.hashCode), value3.hashCode)...
    

    I suggest adopting the "flat" version of the generated hashCode method to

    • allow code generation of class with several hundred fields
    • improve the developer UX for classes with >20 fields by generating in a way to is more friendly to be formatted by dart format
    opened by knaeckeKami 5
Releases(v8.4.2)
  • v8.4.2(Oct 27, 2022)

  • v8.4.1(Aug 19, 2022)

  • v8.4.0(Jul 13, 2022)

    • Fix custom builders in null safe code: allow nested builder fields to be nullable.
    • Improve custom builders for null safe code: allow abstract setter/getter pairs instead of fields. This allows nested builders to have a setter that accepts null and a getter that guarantees not to return null, which is what auto instantiation of nested builders already provides.
    • Allow use of super field initialization in EnumClass.
    Source code(tar.gz)
    Source code(zip)
  • v8.3.3(Jun 17, 2022)

  • v8.3.2(May 24, 2022)

  • v8.3.1(May 24, 2022)

    • Fix generation support for optional generic bounds, e.g. class Foo<T extends Object?>.
    • Fix generation for classes with names starting $.
    • Ignore lint unnecessary_lambdas in generated code.
    Source code(tar.gz)
    Source code(zip)
  • v8.3.0(May 10, 2022)

    • Change generated build methods to return only public types, creating _build methods that return the generated impl types. This means dartdoc will no longer reference the generated types.
    • Ignore the no_leading_underscores_for_local_identifiers lint in generated code.
    • Migrated built_value_generator to null safety. This is purely an internal change, the generator can still generate legacy code as and when needed.
    Source code(tar.gz)
    Source code(zip)
  • v8.2.3(Apr 27, 2022)

  • v8.2.2(Apr 27, 2022)

  • v8.2.1(Apr 26, 2022)

  • v8.2.0(Apr 15, 2022)

    • Allow writing final parameters in EnumClass constructor and valueOf method.
    • Make generator output additional explicit null checks so the generated code complies with the cast_nullable_to_non_nullable lint.
    • Bump version of analyzer.
    Source code(tar.gz)
    Source code(zip)
  • v8.1.4(Jan 14, 2022)

  • v8.1.3(Oct 28, 2021)

  • v8.1.2(Aug 9, 2021)

  • v8.1.1(Jul 9, 2021)

  • v8.1.0(Jun 18, 2021)

    New features:

    • Add @BuiltValueHook annotation. It provides the same functionality as _initializeBuilder and _finalizeBuilder, but in a more visible way: annotate a static method on the value class with @BuiltValueHook to have it called on builder creation or finalization.
    • Add back serializeNulls to BuiltValueSerializer annotation. By default generated serializers skip null fields instead of writing them; set serializeNulls to write the nulls.

    New minor functionality:

    • Support use of nulls in collections when the key or value types are explicitly nullable.
    • Allow JsonObject to be instantiated from a Map<dynamic, dynamic>.
    • Mark nested builder getters in instantiable: false classes not nullable, to match the implementations. Use autoCreateNestedBuilders: false to get the old behaviour.
    • Allow explicit nulls in JSON for nullable fields when deserializing.
    • Specify annotation targets; the analyzer will now hint if a built_value annotation is used where it has no effect.
    • Support polymorphism with mixed in parent value type: generated builder now mixes in parent builder.

    Bug fixes:

    • Fix support for serializing and deserializing nulls.
    • Fix nestedBuilders: false with instantiable: false.
    • Fix enum deserialization fallback for int.
    • Annotating a wrong type getter with @SerializersFor is now an error, instead of just generating nothing.

    Cleanup:

    • Removed Angular mixin from example, as this feature is no longer needed: Angular now directly supports using static members in templates.
    Source code(tar.gz)
    Source code(zip)
  • v8.0.3(Mar 17, 2021)

  • v8.0.1(Mar 9, 2021)

    8.0.1

    • Update chat example to webdev.
    • Allow nulls when serializing/deserializing for better JSON interop.
    • Fix generation bugs around enum wire name and polymorphism.
    • Fix generation with generics for analysis with strict-raw-types.
    • Add test coverage around generation for generic serialization.
    • Add test coverage around initialization with generics.

    Note that you are unlikely to be able to use this version due to version issues; 8.0.2 will be released next for that.

    Source code(tar.gz)
    Source code(zip)
  • v8.0.0(Feb 9, 2021)

  • v7.1.0(Apr 23, 2020)

    • Support private Built classes. Note that private classes cannot be made serializable.
    • Support serializing enums to ints: add wireNumber to @BuiltValueEnumConst.
    • Support memoizing hashCode, so it's computed lazily once. Write an abstract getter int get hashCode; then annotate it with @memoized to turn this on for a built_value class.
    • Trim built_value_test dependencies: depend on matcher instead of test.
    • Fix enum generator error messages when value and valueOf are missing.
    Source code(tar.gz)
    Source code(zip)
  • v7.0.9(Feb 7, 2020)

  • v7.0.8(Jan 16, 2020)

  • v7.0.7(Jan 16, 2020)

    • Fix regression in a corner case when determining which fields to generate based on mixins.
    • Tweak generation changes for implicit-casts: false and implicit-dynamic: false. Relax casts again where possible.
    Source code(tar.gz)
    Source code(zip)
  • v7.0.6(Jan 15, 2020)

    • Make generated code comply with analyzer option strict-raw-types.
    • Allow Serialiers declaration to comply with strict-raw-types, or to continue to use raw types as before.
    • Make generated code comply with analyzer options implicit-casts: false and implicit-dynamic: false.
    Source code(tar.gz)
    Source code(zip)
  • v7.0.3(Jan 1, 2020)

  • v7.0.2(Dec 31, 2019)

Owner
Google
Google ❤️ Open Source
Google
A Flutter repo with a ready-to-go architecture containing flavors, bloc, device settings, json serialization and connectivity

Flutter Ready to Go A Flutter repo with a ready-to-go architecture containing flavors, bloc, device settings, json serialization and connectivity. Why

null 139 Nov 11, 2022
A port of kotlin-stdlib for Dart/Flutter including immutable collections (KtList, KtMap, KtSet) and other packages

kt.dart This project is a port of Kotlin's Kotlin Standard library for Dart/Flutter projects. It's a useful addition to dart:core and includes collect

Pascal Welsch 460 Jan 9, 2023
Github Trending app built with Flutter+Redux+Built(Immutable Data)

Github Trending app built with Flutter+Redux+Built(Immutable Data)

huangyanxiong 9 May 13, 2020
Immutable Dart collections via the builder pattern.

Built Collections for Dart Introduction Built Collections are immutable collections using the builder pattern. Each of the core SDK collections is spl

Google 250 Dec 20, 2022
Neha Tanwar 4 Feb 2, 2022
Awesome Flutter Snippets is a collection snippets and shortcuts for commonly used Flutter functions and classes

Awesome Flutter Snippets Awesome Flutter Snippets is a collection of commonly used Flutter classes and methods. It increases your speed of development

Neevash Ramdial (Nash) 139 Dec 9, 2022
A JSON serialize class to convert 'to' and 'from' JSON format Enums, DateTime and any of your own classes.

A JSON serialize class to convert 'to' and 'from' JSON format Enums, DateTime and any of your own classes. Introduction Jsonize solves the problem of

null 2 Nov 17, 2022
Lightweight and blazing fast key-value database written in pure Dart.

Fast, Enjoyable & Secure NoSQL Database Hive is a lightweight and blazing fast key-value database written in pure Dart. Inspired by Bitcask. Documenta

HiveDB 3.4k Dec 30, 2022
Experimenting with 6 examples of different types of simple and complex JSON structures in Flutter

Parsing complex JSON in Flutter Gives a detailed explanation of working with simple and complex JSON structures using dart:convert library in Flutter

Pooja Bhaumik 488 Jan 6, 2023
Lightweight and blazing fast key-value database written in pure Dart.

Fast, Enjoyable & Secure NoSQL Database Hive is a lightweight and blazing fast key-value database written in pure Dart. Inspired by Bitcask. Documenta

HiveDB 3.4k Dec 30, 2022
A Dart package that helps to implement value based equality without needing to explicitly override == and hashCode.

Simplify Equality Comparisons Overview Being able to compare objects in Dart often involves having to override the == operator as well as hashCode. No

Felix Angelov 747 Jan 8, 2023
A fast, extra light and synchronous key-value storage to Get framework

get_storage A fast, extra light and synchronous key-value in memory, which backs up data to disk at each operation. It is written entirely in Dart and

Jonny Borges 257 Dec 21, 2022
ITS A SIMPLE CRYPTO APP THAT GIVES OR DISPLAYS PRICES - %CHANGE AND CHANGE VALUE OF TICKER (VARIOUS CRYPTO ASSERTS)

btcpricetracker A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started

jatin upadhyay 0 Dec 28, 2021
Flutter Navigation - all types of navigation in flutter run main.tabBar.dart to see tabBar, and run main.dart to see the otheres

pop_up_bar A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if th

Michael Odumosu 0 Jan 1, 2022
This package allows you to scroll/select the value directly from the dropdown with less effort and time.

Direct Select This package allows you to scroll/select the value directly from the dropdown with less effort and time. Inspired by Virgil Pana shot Sa

Diego Velásquez López 62 Nov 25, 2022
Its a simple app which gives Weather Update, Bit Coin Value Comparator, and Flash Chat Application

Bundle_App_MajorProject Description : Its a simple app which is a bundle of Weather Update App, Bit Coin Value Comparator App, and Flash Chat Applicat

Avinandan Bose 2 Sep 9, 2022
Ruqe brings the convenient types and methods found in Rust into Dart, such as the Result, Option, pattern-matching, etc.

ruqe Ruqe brings the convenient types and methods found in Rust into Dart, such as the Result, Option, pattern-matching, etc. Additionally, the librar

Alexander Nitiola 12 Dec 28, 2022
Create dart data classes easily, fast and without writing boilerplate or running code generation.

Dart Data Class Generator Create dart data classes easily, fast and without writing boilerplate or running code generation. Features The generator can

null 186 Feb 28, 2022
Zooper flutter encoding utf16 - Helper classes to encode and decode UTF16 string to List

zooper_flutter_encoding_utf16 Helper classes to encode and decode UTF16 string t

Zooper 0 Feb 10, 2022