THIS PROJECT IS IN PROOF OF CONCEPT STAGE AND IS DEFINITELY NOT SUITABLE FOR USE IN PRODUCTION
Automap is a code generation tool that automates creation of mappings between different types. Resulting code operates without any additional runtime or reflection, so it doesn't incur any runtime overhead compared to handwritten mappings. Most of problems with generating mappings will happen at compile time, unlike other automapping solutions based on reflection that tend to fail at runtime. Finally, generated mappings are susceptible to code analysis tools and can also be easily navigated manually.
This tool is heavily inspired by:
- Wire: dependency injection framework for Go based on code generation
- AutoMapper: convention-based object-object mapper in .NET
Install AutoMap by running:
go get github.com/skhoroshavin/automap/cmd/automap
and ensuring that $GOPATH/bin is added to your $PATH.
Suppose you want to create a mapping from type User to UserDTO.
To do so first you need to create an automap.go file in your project with
the following contents:
//go:build automap
package mypackage
import "github.com/skhoroshavin/automap"
func UserToDTO(user *User) *UserDTO {
panic(automap.Build())
}Note that:
- it starts with build tag
automapwhich prevents this file from compiling during normal build process - it contains mapper function with desired signature
- implementation of that mapper function is just a stub which panics with the
result of marker function
automap.Build()
Then run automap tool in same directory which will create automap_gen.go
file with roughly following contents:
// Code generated by automap. DO NOT EDIT.
//go:build !automap
//go:generate automap
package mypackage
func UserToDTO(user *User) *UserDTO {
return &UserDTO{
FirstName: user.FirstName,
LastName: user.LastName,
AddressCode: user.Address.Code,
StreetAndCity: user.Address.StreetAndCity(),
Country: user.Address.Country,
PrefsGolang: user.Prefs().Golang,
PrefsCompiled: user.Prefs().Compiled(),
}
}Note that:
- it starts with
!automapbuild tag, so it doesn't interfere with subsequent runs of this tool - it includes
go:generatestatement, so mappings can be updated just with normalgo generatecalls, no need to explicitly runautomapafter first bootstrapping - it doesn't import anything related to
automapanymore - generated mapper has same signature as initial stub, and contains explicit mapping of fields that have matching names
- matching is smart enough to use getters or nested queries if needed
- if target type has fields that cannot be matched to any of inputs mapping
generation will fail - this will prevent accidentally creating incomplete
mappings
- Making this behaviour configurable (for example by somehow providing custom mappings for such fields) is planned in future versions.