Passionate Software Developer who likes to have countless private projects which will probably never be finished
-
🔭 I’m currently working on smartstruct
-
🌱 I’m currently learning Flutter, Dart
-
💬 Ask me about Flutter, Dart
Dart Code Generator for generating mapper classes
🔭 I’m currently working on smartstruct
🌱 I’m currently learning Flutter, Dart
💬 Ask me about Flutter, Dart
Lists should be mappable too.
When the sourcefield contains an iterable, we iterate through it, and map it respectively to the target field.
Primitive types will just map to itself, so we can also just create a new list with the old values in it.
Lists of nested Beans will call the mapping method, provided in the mapper class.
class NestedTarget {
NestedTarget(this.subNested);
final List<SubNestedTarget> subNested;
}
class NestedSource {
NestedSource(this.subNested);
final List<SubNestedSource> subNested;
}
@Mapper()
abstract class NestedMapper {
@Mapping(source: 'subNestedSource', target: 'subNestedTarget')
NestedTarget fromModel(NestedSource model);
SubNestedTarget fromSubClassModel(SubNestedSource model);
}
Should generate something like this.
class NestedMapperImpl extends NestedMapper {
@override
NestedTarget fromModel(NestedSource model) {
final nestedtarget = NestedTarget(model.subNested.map((e) => fromSubClassModel(e)).toList(););
return nestedtarget;
}
@override
SubNestedTarget fromSubClassModel(SubNestedSource model) {
final subnestedtarget = SubNestedTarget(model.myProperty);
return subnestedtarget;
}
}
Hi and thank you for work
I have to use other mapper inside my mapper for mapping nested element of my model to entity
But currently I have to copy same method from other mapper
Mapper method should be able to accept multiple parameters, which will map into one target entity.
FooBar fromFoo(Foo foo, Bar bar);
Hello,
I want to ask is smartstruct support to mapping class with generic type?
Thank you
Let's say I have these classes:
class Product {
final int id;
final Money price;
}
class ProductDTO {
final int id;
final num price;
}
class Money {
final num cents;
}
Is it possible to map Product
to ProducMap
and vise versa using your package?
For now we have to create mapper instance:
final mapper = SomeMapperImpl();
final entities = models.map(mapper.fromModel);
It would be greate to use mappers as static
final entities = models.map(SomeMapper.fromModel);
Something like this:
@Mapper()
abstract class EntityMapper {
static Entity fromModel(Model model) => _$EntityMapperFromModel(model);
}
Der Generator soll als Library auf https://pub.dev/ zur verfügung stehen
Siehe https://dart.dev/tools/pub/publishing
Dazu dann auch Doku schreiben
Will it be possible to map objects that inherit other objects?
i.e.
class BaseClass {
BaseClass({required this.id});
final String id;
}
class MyClass extends BaseClass {
MyClass({required this.name, required String id}) : super(id: id);
final String name;
}
I haven't managed to map my freezed objects successfully. Is this possible at this stage?
Hi. I`m using Smartstruct create mapper from UserResponse -> UserModel
Version
smartstruct: ^1.4.0
smartstruct_generator: ^1.4.0
freezed_annotation: ^2.2.0
freezed: ^2.3.2
UserResponse class
`@freezed
class UserResponse with _$UserResponse {
const factory UserResponse(
{@jsonkey(name: 'id') String? id,
@jsonkey(name: 'name') String? name,
@jsonkey(name: 'phone') String? phone,
@jsonkey(name: 'email') String? email,
@jsonkey(name: 'birthday') String? birthday,
@jsonkey(name: 'avata') String? avatar,
@jsonkey(name: 'status') String? status,
@jsonkey(name: 'gender') String? gender}) = _UserResponse;factory UserResponse.fromJson(Map<String, dynamic> json) => _$UserResponseFromJson(json);
}
`
UserModel class
@freezed class UserModel with _$UserModel { const factory UserModel( {String? id, String? name, String? phone, String? email, String? birthday, String? avatar, String? status, String? gender}) = _UserModel; }
Finally class Mapper
`part 'user_mapper.mapper.g.dart';
@Mapper()
abstract class UserMapper {
@mapping(
target: 'copyWith',
ignore: true) // drawback as freezed generates a getter for the copyWith, and we have no way of determining that the copyWith shouldn't be mapped without explicitly ignoring it
UserModel fromModel(UserResponse model);
}
`
Build error -> Bad state: No element
I'm looking for help, is there anyone who can help me?
When i upgrade the flutter version i got this error when generating mapper on version 1.2.4+1
Mapper got case insensitive fields and contains fields: box and box. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.
I tried to upgrade the package to 1.2.6
but i got this error
Because smartstruct_generator >=1.2.5 depends on path ^1.8.1 and every version of flutter_test from sdk depends on path 1.8.0, smartstruct_generator >=1.2.5 is incompatible with flutter_test from sdk. So, because app depends on both flutter_test from sdk and smartstruct_generator ^1.2.6, version solving failed.
Hi,
this library looks great! What about implementing the uses
feature in the @Mapper
annotation?
https://mapstruct.org/documentation/dev/reference/html/#_advanced_mapping_options
Using this flag, developers can reduce the code duplication to map existing objects, by plugging other mappers into the parent one.
// TARGET
class ParentTarget {
ParentTarget(this.childTarget);
final ChildTarget childTarget;
}
class ChildTarget {
ChildTarget(this.property);
final String property;
}
// SOURCE
class ParentSource {
ParentSource(this.childSource);
final ChildSource childSource;
}
class ChildSource {
ChildSource(this.property);
final String property;
}
@Mapper()
abstract class ChildMapper {
@Mapping(source: 'childSource', target: 'childTarget')
ChildTarget toChildTarget(ChildSource model);
}
@Mapper(uses: [ChildMapper])
abstract class ParentMapper {
ParentTarget toParentTarget(ParentSource model);
}
The generated code should be something like down below.
class ParentMapperImpl extends ParentMapper {
final ChildMapper childMapper;
ParentMapperImpl({
required this.childMapper,
}) : super();
ParentTarget toParentTarget(ParentSource model) {
final parentTarget = ParentTarget(childMapper.toChildTarget(model.childSource));
return parentTarget;
}
}
Hi teams,
Please update the package. I am getting error below error.
D:\startup\app\demo_application
dart run build_runner build
Building package executable... (1.0s)
Built build_runner:build_runner.
[INFO] Generating build script completed, took 277ms
[WARNING] Throwing away cached asset graph because the language version of some package(s) changed. This would most commonly happen when updating dependencies or changing your min sdk constraint.
[INFO] Cleaning up outputs from previous builds. completed, took 28ms
[INFO] Generating build script completed, took 78ms
[WARNING] Invalidated precompiled build script due to missing asset graph.
[INFO] Precompiling build script... completed, took 1.1s
[INFO] Building new asset graph completed, took 1.4s
[INFO] Checking for unexpected pre-existing outputs. completed, took 0ms
[WARNING] retrofit_generator on test/widget_test.dart:
Your current `analyzer` version may not fully support your current SDK version.
Analyzer language version: 3.1.0
SDK language version: 3.4.0
Please update to the latest `analyzer` version (6.7.0) by running
`flutter packages upgrade`.
If you are not getting the latest version by running the above command, you
can try adding a constraint like the following to your pubspec to start
diagnosing why you can't get the latest version:
dev_dependencies:
analyzer: ^6.7.0
[WARNING] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:
Bad state: No element
[WARNING] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:
#0 Iterable.first (dart:core/iterable.dart:643:7)
#1 _chooseConstructor (package:smartstruct_generator/code_builders/method_builder.dart:121:71)
#2 _generateBody (package:smartstruct_generator/code_builders/method_builder.dart:62:29)
#3 buildMapperImplementation.<anonymous closure> (package:smartstruct_generator/code_builders/method_builder.dart:26:14)
#4 _$MethodBuilder.update (package:code_builder/src/specs/method.g.dart:323:33)
#5 new _$Method (package:code_builder/src/specs/method.g.dart:38:29)
#6 buildMapperImplementation (package:smartstruct_generator/code_builders/method_builder.dart:22:10)
#7 _generateMapperImplementationClass.<anonymous closure>.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:83:15)
#8 MappedIterator.moveNext (dart:_internal/iterable.dart:403:20)
#9 List.addAll (dart:core-patch/growable_array.dart:319:13)
#10 ListBuilder.addAll (package:built_collection/src/list/list_builder.dart:98:14)
#11 _generateMapperImplementationClass.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:80:17)
#12 _$ClassBuilder.update (package:code_builder/src/specs/class.g.dart:345:33)
#13 new _$Class (package:code_builder/src/specs/class.g.dart:40:28)
#14 _generateMapperImplementationClass (package:smartstruct_generator/code_builders/class_builder.dart:73:10)
#15 buildMapperClass.<anonymous closure> (package:smartstruct_generator/code_builders/class_builder.dart:16:11)
#16 _$LibraryBuilder.update (package:code_builder/src/specs/library.g.dart:226:33)
#17 new _$Library (package:code_builder/src/specs/library.g.dart:28:30)
#18 buildMapperClass (package:smartstruct_generator/code_builders/class_builder.dart:14:10)
#19 MapperGenerator.generateForAnnotatedElement (package:smartstruct_generator/generators/mapper_generator.dart:27:26)
#20 GeneratorForAnnotation.generate (package:source_gen/src/generator_for_annotation.dart:61:30)
#21 _generate (package:source_gen/src/builder.dart:342:33)
<asynchronous suspension>
#22 Stream.toList.<anonymous closure> (dart:async/stream.dart:1351:9)
<asynchronous suspension>
#23 _Builder._generateForLibrary (package:source_gen/src/builder.dart:107:9)
<asynchronous suspension>
#24 _Builder.build (package:source_gen/src/builder.dart:99:5)
<asynchronous suspension>
#25 runBuilder.buildForInput (package:build/src/generate/run_builder.dart:83:7)
<asynchronous suspension>
#26 Future.wait.<anonymous closure> (dart:async/future.dart:524:21)
<asynchronous suspension>
#27 scopeLogAsync.<anonymous closure> (package:build/src/builder/logging.dart:32:40)
<asynchronous suspension>
[SEVERE] smartstruct_generator:mapper on lib/model/mapper/smart_struct.dart:
Bad state: No element
dart:core Iterable.first
package:smartstruct_generator/code_builders/method_builder.dart 121:71 _chooseConstructor
package:smartstruct_generator/code_builders/method_builder.dart 62:29 _generateBody
package:smartstruct_generator/code_builders/method_builder.dart 26:14 buildMapperImplementation.<fn>
package:code_builder/src/specs/method.g.dart 323:33 _$MethodBuilder.update
package:code_builder/src/specs/method.g.dart 38:29 new _$Method
package:smartstruct_generator/code_builders/method_builder.dart 22:10 buildMapperImplementation
package:smartstruct_generator/code_builders/class_builder.dart 83:15 _generateMapperImplementationClass.<fn>.<fn>
dart:core List.addAll
package:built_collection/src/list/list_builder.dart 98:14 ListBuilder.addAll
package:smartstruct_generator/code_builders/class_builder.dart 80:17 _generateMapperImplementationClass.<fn>
package:code_builder/src/specs/class.g.dart 345:33 _$ClassBuilder.update
package:code_builder/src/specs/class.g.dart 40:28 new _$Class
package:smartstruct_generator/code_builders/class_builder.dart 73:10 _generateMapperImplementationClass
package:smartstruct_generator/code_builders/class_builder.dart 16:11 buildMapperClass.<fn>
package:code_builder/src/specs/library.g.dart 226:33 _$LibraryBuilder.update
package:code_builder/src/specs/library.g.dart 28:30 new _$Library
package:smartstruct_generator/code_builders/class_builder.dart 14:10 buildMapperClass
package:smartstruct_generator/generators/mapper_generator.dart 27:26 MapperGenerator.generateForAnnotatedElement
package:source_gen/src/generator_for_annotation.dart 61:30 GeneratorForAnnotation.generate
package:source_gen/src/builder.dart 342:33 _generate
dart:async Stream.toList.<fn>
package:source_gen/src/builder.dart 107:9 _Builder._generateForLibrary
package:source_gen/src/builder.dart 99:5 _Builder.build
[INFO] Running build completed, took 14.9s
[INFO] Caching finalized dependency graph completed, took 73ms
[SEVERE] Failed after 15.0s
research travis for CI possibilities
Hi, this is a great package thanks for sharing. I did look at the documentation and did not see anything like...
For example, I have the class
class UserResponse { final String profile; ... }
And I have
enum UserProfile { investor, consumer }
class User {
final UserProfile profile;
...
}
How can I make the mapper to map with a custom logic for example:
profile: enumFromString<UserProfile>(
UserProfile.values,
response.profile,
UserProfile.consumer,
)
for the profile field. This is just one example there is several more like
class UserResponse {
final String zipCode;
final String number;
final String street;
...
}
Map to
class User {
final Address address;
}
right now the annotations are in the same library as the generator, so you have to add smartstruct as a normal dependency, not as a dev dependency to be able to use it.
Maybe do something like injectable.
Where the generator and annotation are seperated from each other in 2 different libraries
Correct. In this pull #73 I also added Enum as a default to be ignored by static mapping.
So currently you will need the annotation, in 1.3.1 it will be ignored by default.
Originally posted by @smotastic in #68 (comment)
(Just for reference, Issue was fixed in #73)
Hello, I am going to apply smartstruct packages to my company projects. I am using freezed & injectable.
I want you to add a new feature for smartstruct with injectable.
This code is what I have written.
class DependencyOrder {
static const int dataMapper = 1; // mapper
}
class DataMapper extends Injectable {
const DataMapper({
super.as,
super.env,
super.scope,
}) : super(order: DependencyOrder.dataMapper);
abstract class Mappable<M, E> {
M call(E entity);
}
@DataMapper(as: Mappable<User, UserRes>)
class UserMapper implements Mappable<User, UserRes> {
@override
User call(UserRes entity) {
return User(
admin: entity.admin,
email: entity.email,
imageUrl: entity.imageUrl.isNotEmpty ? entity.imageUrl : null,
name: entity.name,
);
}
}
I want to convert my UserMapper class to same one with smart struct.
I have a problem with now version of smart struct. 1.4.0
User & UserRes class is composed of freezed.
If I apply smart struct to this code, I should change UserMapper to abstract class.
And I also would set useInjectable to true.
Then UserMapperImpl class generated by build_runner would have a @LazySingleton(as: UserMapper).
I want to custom value of as. not UserMapper but Mappable<User, UserRes>
// custom singleton or injectable or lazySingleton
@Injectable(
as: Mappable<User, UserRes>, // custom
order: DependencyOrder.dataMapper, // custom
)
class UserMapperImpl implements UserMapper {
// generated code ...
}
I hope you to add this feature that custom injectable properties.
Right now the first found constructor is used for populating data initially.
ConstructorElement _chooseConstructor(
ClassElement outputClass, ClassElement _) {
return outputClass.constructors.where((element) => !element.isFactory).first;
}
It would be nice, if in the Mapping Annotation you can define the constructor to use.
class Bar {
final String text;
Bar() : this.text = 'should not be used by mapper';
Bar.useThis(this.text);
}
@Mapper()
class Mapper {
@Mapping(constructor='useThis')
Foo fromBar(Bar source);
}
Generated Mapper should then use the "useThis" constructor.
In the future we might use constructor tear off, right now it's not supported by dart and only in the beta.
https://github.com/dart-lang/language/blob/master/accepted/future-releases/constructor-tearoffs/feature-specification.md
After upgrade to Flutter 3.10, I excuted the build runner to process:
flutter pub run build_runner build --delete-conflicting-outputs
Output:
Invalid argument(s): Required input cycle for [{autoApply: AutoApply.dependents, import: package:smartstruct_generator/integrations/builder.dart, builderFactories: [smartstructBuilder], buildExtensions: {.dart: [mapper.g.dart]}, requiredInputs: [.g.dart], runsBefore: [injectable_generator:injectable_builder], isOptional: false, buildTo: BuildTo.source, defaults: Instance of 'TargetBuilderConfigDefaults'}]
I believe this issue caused by the new build_runner
updated:
How can I fix it ? Thanks
Hi,
I'm using the OpenApi Generator to generate my ApiClient and Backend Models with JSON Serialization and want to Auto Map the backend Model into my Entities, which declared as freezed Models. So my generated Model looks like this:
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// ignore_for_file: unused_element
import 'package:json_annotation/json_annotation.dart';
part 'api_country.g.dart';
@JsonSerializable(
checked: true,
createToJson: true,
disallowUnrecognizedKeys: false,
explicitToJson: true,
)
class ApiCountry {
/// Returns a new [ApiCountry] instance.
ApiCountry({
required this.id,
this.name,
this.isoCode,
});
@JsonKey(
name: r'id',
required: true,
includeIfNull: false
)
final int id;
@JsonKey(
name: r'name',
required: false,
includeIfNull: false
)
final String? name;
@JsonKey(
name: r'isoCode',
required: false,
includeIfNull: false
)
final String? isoCode;
@override
bool operator ==(Object other) => identical(this, other) || other is ApiCountry &&
other.id == id &&
other.name == name &&
other.isoCode == isoCode;
@override
int get hashCode =>
id.hashCode +
name.hashCode +
isoCode.hashCode;
factory ApiCountry.fromJson(Map<String, dynamic> json) => _$ApiCountryFromJson(json);
Map<String, dynamic> toJson() => _$ApiCountryToJson(this);
@override
String toString() {
return toJson().toString();
}
}
and my Freezed Entity like this:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'country.freezed.dart';
@freezed
class Country with _$Country {
const factory Country({
required int id,
String? name,
String? isoCode
}) = _Country;
}
Now I want to create a Mapper class like this:
import 'package:domain/domain.dart';
import 'package:injectable/injectable.dart';
import 'package:sample_api_client/sample_api_client.dart';
import 'package:smartstruct/smartstruct.dart';
part 'country_mapper.mapper.g.dart';
@Mapper(useInjection: true)
abstract class CountryMapper {
@Mapping(target: "copyWith", ignore: true)
Country fromModel(ApiCountry model);
}
But on generation I'm getting the Bad state: no element
error, like in another thread for freezed. I think this results from not mapping freezed into freezed, so the question is: Will this possible in the future or did I oversee something?
Thanks in advance, maybe I can find a way myself.
Mapper got case insensitive fields and contains fields: data and data. If you use a case-sensitive mapper, make sure the fields are unique in a case insensitive way.
I'm using the latest version. This was still working v1.2.3+1
Write some tests for the generator
Turns out travis is not so free anymore.
Let's see if Github proves more useful
Given the following source and target classes:
// Sources
class UserContract {
UserContract(this.address);
final AddressContract address;
}
class AddressContract {
AddressContract(this.name);
final String? name;
}
// Targets
class UserEntity {
UserEntity(this.address);
final AddressEntity address;
}
class AddressEntity {
AddressEntity(this.name);
final String? name;
}
Then our mapper would be like this:
// user_mapper.dart
@Mapper(useInjection: true)
abstract class UserMapper {
UserEntity fromContract(UserContract contract);
AddressEntity fromAddressContract(AddressContract contract);
}
// user_mapper.mapper.g.dart
@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
@override
UserEntity fromContract(UserContract contract) {
final userentity = UserEntity(fromAddressContract(contract.address));
return userentity;
}
@override
AddressEntity fromAddressContract(AddressContract contract) {
final addressentity = AddressEntity(contract.name);
return addressentity;
}
}
There will be instances that we would need a separate mapper for Address
, and we would then create:
// address_mapper.dart
@Mapper(useInjection: true)
abstract class AddressMapper {
AddressEntity fromContract(AddressContract contract);
}
// address_mapper.mapper.g.dart
@LazySingleton(as: AddressMapper)
class AddressMapperImpl extends AddressMapper {
@override
AddressEntity fromContract(AddressContract contract) {
final addressentity = AddressEntity(contract.name);
return addressentity;
}
}
To reuse the logic from AddressMapper
, we resolve AddressMapper
in UserMapper
and use it for mapping subclasses of UserContract
in UserMapper.fromAddressContract
. Right now we can do this by:
// user_mapper.dart
@Mapper(useInjection: true)
abstract class UserMapper {
UserEntity fromContract(UserContract contract);
@nonVirtual
AddressEntity fromAddressContract(AddressContract contract) =>
locator<AddressMapper>().fromContract(contract); // inline resolving using `get_it`
}
// user_mapper.mapper.g.dart
@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
@override
UserEntity fromContract(UserContract contract) {
final userentity = UserEntity(fromAddressContract(contract.address));
return userentity;
}
// UserMapper.fromAddressContract will not be generated since it was marked `nonVirtual`
}
It would be better if we can do the following:
// user_mapper.dart
@Mapper(useInjection: true)
abstract class UserMapper {
final AddressMapper _addressMapper;
UserMapper(this._addressMapper); // constructor-injected
UserEntity fromContract(UserContract contract);
@nonVirtual
AddressEntity fromAddressContract(AddressContract contract) =>
_addressMapper.fromContract(contract);
}
But the problem is that the generated mapper doesn't call the base constructor. The generated class should be:
// user_mapper.mapper.g.dart
@LazySingleton(as: UserMapper)
class UserMapperImpl extends UserMapper {
UserMapperImpl(AddressMapper addressMapper) : super(addressMapper); // call super
@override
UserEntity fromContract(UserContract contract) {
final userentity = UserEntity(fromAddressContract(contract.address));
return userentity;
}
}
Hi!
I have below an abstract class that maps one object to another:
abstract class ContractFromEntityMapper<C extends DataContract, E extends DomainEntity> {
C? fromEntity(E? entity);
}
Then I inherit this to another class which will also be used to generate the mapper:
@Mapper(useInjection: true)
abstract class UserLoginContractFromEntityMapper extends ContractFromEntityMapper<UserLoginContract, UserLoginEntity> {}
After running build_runner
, the generated file does not include fromEntity
method:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_login_mapper.dart';
// **************************************************************************
// MapperGenerator
// **************************************************************************
@LazySingleton(as: UserLoginContractFromEntityMapper)
class UserLoginContractFromEntityMapperImpl
extends UserLoginContractFromEntityMapper {
UserLoginContractFromEntityMapperImpl() : super();
}
But when explicitly adding the fromEntity
method in UserLoginContractFromEntityMapper
:
@Mapper(useInjection: true)
abstract class UserLoginContractFromEntityMapper extends ContractFromEntityMapper<UserLoginContract, UserLoginEntity> {
@override
UserLoginContract? fromEntity(UserLoginEntity? entity);
}
the generated file is complete:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_login_mapper.dart';
// **************************************************************************
// MapperGenerator
// **************************************************************************
@LazySingleton(as: UserLoginContractFromEntityMapper)
class UserLoginContractFromEntityMapperImpl
extends UserLoginContractFromEntityMapper {
UserLoginContractFromEntityMapperImpl() : super();
@override
UserLoginContract? fromEntity(UserLoginEntity? entity) {
if (entity == null) {
return null;
}
;
final userlogincontract =
UserLoginContract(email: entity.email, password: entity.password);
return userlogincontract;
}
}
Thanks for the library. I'm a fan of Mapstruct and it's good to see a similar effort in the dart world.
One question or feature request. Is it possible to exclude a field from the automatic mapper, something similar to this?
The less we explicitly name the fields, the easier it becomes to maintain the mappings. This is particularly relevant when using libraries like Equatable that add helper fields we do not want to include in our mappings.
This would allow scenarios where we could say "map all fields except this one" as opposed to having to explicitly map all the ones we want.
Ich will im Mapper konfigurieren können, ob dieser Mapper injectable ist.
Dann muss der Impl einfach nur eine zusätzliche Annotation
@LazySingleton(as: abstractclass)
hinzugefügt werden
@smotastic Hi, thanks for info.
I've tested new commits and unfortunately there is still broken Static mapping.
With this new change, it is not possible add helper methods for map Enums, List, Maps, Set or anything that is not a class as it generates invalid code
static EnumFoo _mapEnumFoo(Source model) => model.foo ...
static List<String> _mapNames(Source model) => model.friends.map((f) => f.name).toList()
both will generate something like
EnumFoo _$_mapEnumFoo(Source model) {
final enumFoo = EnumFoo._();
return enumFoo;
}
for List it wil generate similar code.
So for now within my fork I've completely reverted static mapping as it is not usable in my application.
Originally posted by @petrnymsa in #58 (comment)
Is it possible to map classes with subclasses?
// Input
class MyClass {
MyClass(this.mySubClass);
final MySubClass mySubClass;
}
class MySubClass {
MySubClass(this.myProperty);
final String myProperty;
}
// Output
class MyClassModel {
MyClassModel(this.mySubClass);
final MySubClassModel mySubClass;
}
class MySubClassModel {
MySubClassModel(this.myProperty);
final String myProperty;
}
Given below the my mapper class:
@Mapper(useInjection: true)
abstract class UserSigninMapper {
UserSigninContract? fromEntity(UserSigninEntity? entity);
}
and the generated file contains:
@LazySingleton(as: UserSigninMapper)
class UserSigninMapperImpl extends UserSigninMapper {
@override
UserSigninContract? fromEntity(UserSigninEntity? entity) {
if (entity == null) {
return null;
}
;
final usersignincontract =
UserSigninContract(email: entity.email, password: entity.password);
return usersignincontract;
}
}
Running flutter pub run build_runner build
shows the following output:
[INFO] Running build...
// Removed for brevity
[AuthManagerImpl] depends on unregistered type [UserSigninMapper] from my_app/domain/mappers/authentication/user_signin_mapper.dart
Did you forget to annotate the above class(s) or their implementation with @injectable?
------------------------------------------------------------------------
// Removed for brevity
[INFO] Succeeded after 19.2s with 14 outputs (90 actions)
It seems that UserSigninMapper
is not being registered. I think build_runner
is ignoring generated files.
Nullable lists are not being mapped properly.
My Model contains: List<String>? values;
Generated mapper contains: values: entity.values.map((e) => e).toList()
which results in error "The method 'map' can't be unconditionally invoked because the receiver can be 'null'"
Shouldn't it be values: entity.values!.map((e) => e).toList()
Originally posted by @gopalsabhadiya in #12 (comment)
I am trying to generate mapper using this lb but not file is getting generated.
Perhaps doesn't work with Realm
Code:
import 'package:deckinspectors/src/models/project_model.dart';
import 'package:deckinspectors/src/models/realm/realm_schemas.dart';
import 'package:smartstruct/smartstruct.dart';
@Mapper()
abstract class ChildMapper {
Child? fromLocalChild(LocalChild? localChild);
LocalChild fromChild(Child project);
}
Here, LocalChild class is a Realm generated.
Auf Methodeneben möchte ich einstellen können wie gewisse Fields im in- und output gemapped werden, falls diese nicht den gleichen Namen haben.
Siehe Mapstruct
@mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car); 2
It would be very helpful to have annotations for BeforeMapping & AfterMapping like the original mapstruct has.
Example usage:
class Source {}
class Target {
Service _service;
void setSevice(Service service) {
_service = service;
}
}
@Mapper()
abstract class SourceToTargetMapper {
Service _service;
SourceToTargetMapper(Service service) {
_service = service;
}
Target fromSource(Source source);
@AfterMapping()
void afterMapping(Target target) {
target.setService(_service);
}
}
Often classes contains getters without explicit setter (computed getter,...). In such case, generated code tries to assign value to them.
Run smartstruct 1.4.0 against this mapper:
class GetterTarget {
final String name;
final int age;
int foo = 0;
GetterTarget({
required this.name,
required this.age,
});
List<Object?> get props => [name, age];
bool get sample => false;
}
class GetterSource {
final String name;
final int age;
int foo = 1;
GetterSource({
required this.name,
required this.age,
});
List<Object?> get props => [name, age];
bool get sample => true;
}
@Mapper()
abstract class GetterMapper {
GetterTarget fromModel(GetterSource source);
}
Generated mapping
class GetterMapperImpl extends GetterMapper {
GetterMapperImpl() : super();
@override
GetterTarget fromModel(GetterSource source) {
final gettertarget = GetterTarget(
name: source.name,
age: source.age,
);
gettertarget.foo = source.foo;
// NO SETTER !
gettertarget.props = source.props.map((e) => e).toList();
// NO SETTER !
gettertarget.sample = source.sample;
return gettertarget;
}
}
This can happen alot if project uses Equatable, where props
, stringify
and hashCode
is used.
Question: How to realize this kind of mapping?
class Target {
final String text1;
final Sourse2 source2;
Target(this.text1, this.source2);
}
class Source {
final String text1;
final int source2Id;
Source(this.text1);
}
class Source2 {
final int id;
final String text2;
Source2(this.text2);
}
"Multiple sources" example is close to that, but not exactly.
Ich möchte eine Singleton Instanz automatisch generieren auf die ich über einen globalen Kontext zugreifen kann.
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
Alles was nach dem constructor call nicht gesetzt wurde / werden konnte könnte noch über setter gesetzt werden.
Sollte nur für fields gelten die nicht final sind
Hi,
Given an example dto like the following, with serializable's toJson / fromJson methods
@JsonSerializable(explicitToJson: true)
class ActivityAssetsDto {
@JsonKey(name: 'image')
final String imageUrl;
const ActivityAssetsDto({this.imageUrl = ""});
factory ActivityAssetsDto.fromJson(Map<String, dynamic> json) =>
_$ActivityAssetsDtoFromJson(json);
Map<String, dynamic> toJson() => _$ActivityAssetsDtoToJson(this);
}
it generates
@override
ActivityAssetsDto fromActivityAssets(ActivityAssets entity) {
final activityassetsdto = ActivityAssetsDto.fromJson();
return activityassetsdto;
}
using "fromJson()" as constructor (obviously without parameter since it doesn't know what tu put there)
if I add a second parameter to the ActivityAssetsDto constructor the generator picks the correct constructors without problems.
It seems that the strategy of getting the constructor with the most arguments does not always work.
thank you for your time
There is new version available and many packages depend on it, so this is breaking version check.
Because smartstruct_generator >=1.3.0 depends on analyzer ^4.0.0 and json_serializable 6.6.0 depends on analyzer ^5.2.0, smartstruct_generator >=1.3.0 is incompatible with json_serializable 6.6.0.
And because no versions of json_serializable match >6.6.0 <7.0.0, smartstruct_generator >=1.3.0 is incompatible with json_serializable ^6.6.0.
So, because example depends on both json_serializable ^6.6.0 and smartstruct_generator ^1.3.0, version solving failed.
pub get failed (1; So, because example depends on both json_serializable ^6.6.0 and smartstruct_generator ^1.3.0, version solving failed.)
If a Mapper needs to be created for a Class which is also generated by source_gen, the mapper generator will throw an error that the source / target class is not a ClassElement.
The problem is, that my generator might, or might not run before the generator which will create the dependend class.
So the smartstruct_generator should always run after all class files which are potentially needed, are created.
See https://pub.dev/packages/build_config#adjusting-builder-ordering
Given the following classes:
class Dog {
final String breed;
final int age;
final String name;
Dog(this.breed, this.age, this.name);
}
class DogModel {
final String breed;
final int age;
final String name;
DogModel(this.breed, this.age, this.name);
}
And given the following mapper interface:
// dogmapper.dart
part 'dogmapper.mapper.g.dart';
@Mapper()
abstract class DogMapper {
Dog asEntity(DogModel model);
}
Instead of generating a mapper class, it would be great to generate mapper extension methods as follows:
// dogmapper.mapper.g.dart
extension ConvertibleDogModel on DogModel {
Dog get asEntity => Dog(breed, age, name);
}
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.