Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation fails if property name is start (substring) of another property #525

Closed
3 of 9 tasks
MasterPG5 opened this issue Dec 19, 2022 · 3 comments · May be fixed by #573
Closed
3 of 9 tasks

Compilation fails if property name is start (substring) of another property #525

MasterPG5 opened this issue Dec 19, 2022 · 3 comments · May be fixed by #573
Labels
bug Something isn't working

Comments

@MasterPG5
Copy link

MasterPG5 commented Dec 19, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

I faced a very strange bug (I think). I have two classes, OrderDto and Order. These classes have 2 properties (among others), of which one is a starting substring of the other: shippingFee and shippingFeePerPallet, both nullable numbers.
I have a mapping profile to map from the former to the latter. First, I didn't specify these in the mapping profile explicitely, but when I tried to build the project, it failed with the following error (at the addProfile function):

.../server/node_modules/@automapper/core/index.cjs:1092
  return Object.prototype.hasOwnProperty.call(obj, property);
                                         ^
[2022.12.19 10:44:47] [error] -  TypeError: Cannot convert undefined or null to object

[...]

at addProfile (.../server/node_modules/@automapper/core/index.cjs:1373:11)

I narrowed down the problem to the shippingFee property. I tried adding both properties to the profile explicitely, as follows:

createMap(
    mapper,
    OrderDto,
    Order,
    forMember(
      (dest) => dest.shippingFee,
      mapFrom((source) => source.shippingFee)
    ),
    forMember(
      (dest) => dest.shippingFeePerPallet,
      mapFrom((source) => source.shippingFeePerPallet)
    )
  );

But it still doesn't work. The way I got it working is that I deleted shippingFee from both the profile and the OrderDto class (not a good solution, but it confirms the source of the issue). Another workaround was that I renamed shippingFee to shipiingFee (yes, with a typo) in both classes, in which case it magically worked.

The strange thing is, that other properties also have this kind of same-starting-substring, but they work without errors (like status and statusEn) - even the workaround has the same substring: shipiingFee and shippingFeePerPallet also start with "ship".

Models/DTOs/VMs

export class OrderDto {
...
  @AutoMap() @Expose() shippingFee?: number;
  @AutoMap() @Expose() shippingFeePerPallet?: number;
...
}

export class Order {
...
  @AutoMap() @Expose() shippingFee?: number;
  @AutoMap() @Expose() shippingFeePerPallet?: number;
...
}

Mapping configuration

createMap(
    mapper,
    OrderDto,
    Order,
    forMember(
      (dest) => dest.shippingFee,
      mapFrom((source) => source.shippingFee)
    ),
    forMember(
      (dest) => dest.shippingFeePerPallet,
      mapFrom((source) => source.shippingFeePerPallet)
    )
  );

Steps to reproduce

  1. Implement the following classes and mapping
  2. Add the profile
  3. Try to build

Expected behavior

Should map the properties to their counterparts as expected.

Screenshots

No response

Minimum reproduction code

No response

Package

  • I don't know.
  • @automapper/core
  • @automapper/classes
  • @automapper/nestjs
  • @automapper/pojos
  • @automapper/mikro
  • @automapper/sequelize
  • Other (see below)

Other package and its version

No response

AutoMapper version

8.7.6

Additional context

No response

@MasterPG5 MasterPG5 added the bug Something isn't working label Dec 19, 2022
@Balint98
Copy link

Balint98 commented Dec 21, 2022

I got the same issue, when I used namingConventions option in your case CamelCaseNamingConvention.

const mapper = createMapper({
    strategyInitializer: classes(),
    namingConventions: new CamelCaseNamingConvention(), // <---
});

If you use namingConventions you enable the autoflattening feature (see: https://automapperts.netlify.app/docs/fundamentals/auto-flattening)
Now Automapper expects your classes to look like this:

export class ShippingFee {
   @AutoMap() @Expose() perPallet?: number;
}

export class OrderDto {
...
  @AutoMap() @Expose() shippingFee?: ShippingFee;
...
}

export class Order {
...
  @AutoMap() @Expose() shippingFeePerPallet?: number;
...
}

And now when you map an OrderDto to Order Automapper will map orderDto.shippingFee.perPallet into order.shippingFeePerPallet

const orderDto = new OrderDto();
const shippingFee = new ShippingFee();
shippingFee.perPallet = 10;
orderDto.shippingFee = shippingFee;

console.log('orderDto', orderDto); // orderDto OrderDto { shippingFee: ShippingFee { perPallet: 10 } }
const order = mapper.map(orderDto, OrderDto, Order);
console.log('order', order); // order Order { shippingFeePerPallet: 10 }

Without the namingConventions it works just fine.

const mapper = createMapper({
    strategyInitializer: classes()
});

@MasterPG5
Copy link
Author

Thank you, @Balint98 , it works for me, too!

Closing the issue.

@abouroubi
Copy link

I don't know why this issue is closed, it's still a problem.

Auto Flattening is a nice to have but shouldn't be mandatory.

I have two models, one with properties named my_property_name and the other is myPropertyName, so I added naming convention, but it forced Auto Flattening on me and now properties that starts with same word are crashing my app.

I think the Auto Flattening should have an option to opt out from it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment