Skip to content

v10.2.0

Latest

Choose a tag to compare

@sanelli sanelli released this 09 Aug 15:11
· 2 commits to main since this release
3390e4c

Mappa 10.2.0 expands mapping control with reference handling and compile-time cycle breaking, IQueryable projection, nested property paths, dependency-injection registrars, inaccessible-member mapping, object factories, before/after hooks, and richer enum / settings options. Benchmarks, coverage tooling, and generator performance also improve.
Full changelog: v10.1.0...v10.2.0

Breaking changes

When upgrading from 10.1.0, see the upgrade guide.

Relaxed nullability matching for existing map methods

  • Nested mappings may reuse an existing map method when nullability annotations differ slightly (#184, #272)
    • With #nullable enable, nested mappings may now invoke an existing map method on the mapper, a dependency, or a matching polymorphic method when the underlying types match even if nullability annotations differ.
    • Exact nullability matches are still preferred; a relaxed match is used only when no exact match exists.
    • Supported relaxations: nested needs TTarget? → may invoke a method returning TTarget; nested needs TSource → may invoke a method accepting TSource?.
    • Previously, a nullability mismatch caused the generator to skip the existing method and generate inline mapping (or select another strategy). Review nested mappings that relied on the old behaviour.

Reference handling

  • Circular reference / reference handling (#249, #307) — Reuse mapped reference-type instances for cycles and shared graphs (ReferenceReusing), limit runtime nesting (MaxRuntimeDepth), and guard generator discovery (MaxCompileTimeDepth + compile-time mapping-cycle detection). Not supported on IQueryable projection.
  • Per-TTarget reference reuse and codegen polish (#320, #321, #322, #333) — Key reuse by source identity and typeof(TTarget), omit redundant AddReferencePair calls, and cache the reference-manager local.
  • BreakCompileTimeCycles (#306, #311) — Optionally break compile-time mapping cycles by synthesizing private map methods; emits MP00078 when a cycle is auto-broken.

New features

  • IQueryable projection (ProjectTo-style) (#245, #284) — Map methods with IQueryable<TSource> → IQueryable<TTarget> emit provider-translatable Select projections. Not compatible with Native AOT ([RequiresDynamicCode]).
  • Nested (dot-separated) property paths (#120, #274, #275, #278) — Use paths such as "Address.City" on MappaUseProperty, invoke, constant, context, and ignore attributes for flattening/unflattening.
  • MappaObjectFactory (#253, #291) — Construct target types via named factory methods instead of new.
  • MappaBeforeMap / MappaAfterMap (#250, #281) — Invoke named hooks immediately before and after the generated root mapping body.
  • MappaMustMapTargetProperty (#20, #298) — Require listed (or all) non-required target properties to be mapped on the empty-constructor path; otherwise MP00065.
  • Inaccessible / private members (#254, #300) — Opt in with MappaAllowInaccessibleSourceMembers / MappaAllowInaccessibleTargetMembers to read/write private or protected members (and invoke inaccessible constructors) via UnsafeAccessor.
  • Generic polymorphic type-mapping attributes (#305, #316) — Prefer MappaTypeMapping<TTarget, TSource> and MappaTypeMappingDefault<TDefault> over non-generic forms.

Dependency injection

  • MappaDependencyInjection attribute (#299, #302) — Generate IServiceCollection registration methods for [Mappa] mappers; static DI mappers are skipped with MP00073.
  • InjectFromAssemblies (#301, #317) — Discover [Mappa] mappers across assemblies for DI registration; Bson and Protobuf DI packages migrate to generated registrars.

MappaSettings and mapping behaviour

  • DictionaryAssignment (#34, #273) — Choose indexer or Add insertion for dictionary-to-dictionary mapping.
  • PreventEnumerableCount (#108, #285) — Avoid Enumerable.Count for fixed-size targets when the source length is unknown.
  • CompatibleMapMethod (#13, #296) — Opt-in reuse of existing map methods when the source is a base/interface type and the method returns a compatible derived type.
  • Richer enum mapping configuration (#255, #282) — Configure enum↔integral, enum↔string, and enum↔enum pairings via MappaMapEnumMember, MappaMapEnumIgnore, and MappaMapEnumDefault.
  • Relaxed nullability fallback for map method matching (#184, #272) — See Breaking changes.

Projection polish

  • Remove unused {MethodName}Element from IQueryable projections (#303, #304) — Stop emitting unused local helpers in projection-generated code.

Generator quality and performance

  • Narrow syntax providers and honor CancellationToken (#323, #325, #335) — Attribute-driven incremental discovery via ForAttributeWithMetadataName, and cooperative cancellation on hot paths.
  • Reduce ReportGenerator CRAP / cyclomatic complexity (#238, #318) — Refactor hotspot methods and enforce CRAP/CC maxima in the coverage script.
  • Branch coverage improvements (#327, #336) — Targeted tests for previously uncovered generator branches; comparison-chart annotation polish.
  • Bug fixes (#319, #328, #329, #330) — Null-class continue path, culture typo, and MappaContext documentation corrections.

Benchmarks and CI tooling

  • Expanded benchmark suite with SVG charts (#134, #286) — Broader mapper scenarios, competitor/Mappa percentage charts, and gist/history publishing.
  • Benchmark display and comparison charts (#295, #297, #309, #315) — Bogus-seeded inputs, refined TIME/MEMORY SVGs, and a winner comparison table.
  • Default BenchmarkDotNet job; skip PR benchmarks (#331, #332) — Reduce flakiness and stop running/commenting benchmarks on pull requests.
  • Coverage history and PR coverage comments (#250, #276, #280, #281) — PR coverage comments with drop thresholds and improved coverage-history SVGs.
  • Gist update retries (#293, #294) — Idempotent history merges with retries on gist updates.

Test infrastructure

  • Stronger generator syntax assertions (#277, #279, #290, #292) — Require HasNextSyntaxNode walks and full validation after HaveGeneratedSourceCode().
  • Diagnostic assertion rules (#310, #313) — Require HaveDiagnostics(n) or NotHaveDiagnostics() on generator test chains.
  • Dump generated sources from generator tests (#308, #312) — Persist successful generation dumps for issue reports.

Maintenance

  • Update outdated NuGet package dependencies (#287, #337) — Bump Roslyn, analyzers, test packages, samples, benchmarks, and integration packages.
  • Release 10.2.0 (#271, #338) — Promote version from 10.2.0-alpha.* to stable 10.2.0.

All pull requests

PR Issue Summary
#272 #184 Relaxed nullability fallback for map method matching
#273 #34 DictionaryAssignment MappaSettings for dictionary-to-dictionary mapping
#274 #120 Nested (dot-separated) property paths in mapping attributes
#278 #275 Flattening/unflattening follow-up
#279 #277 Strengthen nested-path tests with HasNextSyntaxNode assertions
#280 #276 Improve method coverage and coverage history SVG
#281 #250 Before/after map hooks and PR coverage comments
#282 #255 Richer enum mapping configuration
#284 #245 IQueryable projection (ProjectTo)
#285 #108 PreventEnumerableCount MappaSettings option
#286 #134 Better benchmarks across mappers with CI charts and gist history
#291 #253 Object factories
#292 #290 Improve generator tests and assertion rules
#294 #293 Retry gist updates and make history merges idempotent
#296 #13 Opt-in compatible map-method reuse for nested mappings
#297 #295 Update benchmark display
#298 #20 MappaMustMapTargetProperty attribute
#300 #254 Private / inaccessible members
#302 #299 MappaDependencyInjectionAttribute
#304 #303 Remove unused generated MethodNameElement from IQueryable projections
#307 #249 Circular reference / reference handling
#311 #306 Break compile-time mapping cycles by synthesizing private map methods
#312 #308 Dump successfully generated sources from generator tests
#313 #310 Require HaveDiagnostics(count) on generator test diagnostic assertions
#315 #309 Add MAPPA-BENCHMARK-COMPARISON.svg winner table and reorder README benchmarks
#316 #305 Introduce generic polymorphic type-mapping attributes
#317 #301 InjectFromAssemblies for cross-assembly DI mapper discovery
#318 #238 Reduce ReportGenerator CRAP and cyclomatic complexity in Mappa.Generator
#330 #319, #328, #329 Fix null-class continue, culture typo, and MappaContext docs
#332 #331 Use Default BenchmarkDotNet job; skip PR benchmarks
#333 #320, #321, #322 Reference reuse: per-TTarget keys, omit redundant Add, cache manager local
#335 #323, #325 Narrow syntax providers and honor CancellationToken
#336 #327 Improve Mappa.Generator branch coverage and comparison chart annotations
#337 #287 Update outdated NuGet package dependencies
#338 #271 Release 10.2.0