Skip to content

Setting: extend

extend [PACKAGE:]TYPE... can be defined as CLI argument or converter comment.

If a type cannot be converted automatically, you can manually define an implementation with :extend for the missing mapping. Keep in mind, Goverter will use the custom implementation every time, when the source and target type matches.

See signatures for possible method signatures.

extend TYPE

extend TYPE allows you to reference a method in the local package. E.g:

TYPE can be a regex if you want to include multiple methods from the same package. E.g. extend IntTo.*

go
package example

import "fmt"

// goverter:converter
// goverter:extend IntToString
type Converter interface {
	Convert(Input) Output
}
type Input struct {
	Name string
	Age  int
}
type Output struct {
	Name string
	Age  string
}

func IntToString(i int) string {
	return fmt.Sprint(i)
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import extendlocal "github.com/jmattheis/goverter/example/extend-local"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source extendlocal.Input) extendlocal.Output {
	var exampleOutput extendlocal.Output
	exampleOutput.Name = source.Name
	exampleOutput.Age = extendlocal.IntToString(source.Age)
	return exampleOutput
}
Complex example (click to expand)
go
package example

// goverter:converter
// goverter:extend ExtractFriendNames
type Converter interface {
	Convert(source []InputPerson) []OutputPerson
}

type InputPerson struct {
	Name    string
	Friends []InputPerson
}
type OutputPerson struct {
	Name    string
	Friends []string
}

func ExtractFriendNames(persons []InputPerson) []string {
	var names []string
	for _, person := range persons {
		names = append(names, person.Name)
	}
	return names
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import extendlocalcomplex "github.com/jmattheis/goverter/example/extend-local-complex"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source []extendlocalcomplex.InputPerson) []extendlocalcomplex.OutputPerson {
	var exampleOutputPersonList []extendlocalcomplex.OutputPerson
	if source != nil {
		exampleOutputPersonList = make([]extendlocalcomplex.OutputPerson, len(source))
		for i := 0; i < len(source); i++ {
			exampleOutputPersonList[i] = c.exampleInputPersonToExampleOutputPerson(source[i])
		}
	}
	return exampleOutputPersonList
}
func (c *ConverterImpl) exampleInputPersonToExampleOutputPerson(source extendlocalcomplex.InputPerson) extendlocalcomplex.OutputPerson {
	var exampleOutputPerson extendlocalcomplex.OutputPerson
	exampleOutputPerson.Name = source.Name
	exampleOutputPerson.Friends = extendlocalcomplex.ExtractFriendNames(source.Friends)
	return exampleOutputPerson
}

extend PACKAGE:TYPE

You can extend methods from external packages by separating the package path with : from the method.

TYPE can be a regex if you want to include multiple methods from the same package. E.g. extend strconv:A.*

go
package example

// goverter:converter
// goverter:extend strconv:Atoi
type Converter interface {
	Convert(Input) (Output, error)
}

type Input struct{ Value string }
type Output struct{ Value int }
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
	extendexternal "github.com/jmattheis/goverter/example/extend-external"
	"strconv"
)

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source extendexternal.Input) (extendexternal.Output, error) {
	var exampleOutput extendexternal.Output
	xint, err := strconv.Atoi(source.Value)
	if err != nil {
		return exampleOutput, err
	}
	exampleOutput.Value = xint
	return exampleOutput, nil
}

Signatures

Method with converter

You can access the generated converter by defining the converter interface as first parameter.

go
func IntToString(c Converter, i int) string {
    // Use c.ConvertSomething()
    return fmt.Sprint(i)
}
Example (click to expand)
go
package example

// goverter:converter
// goverter:extend ConvertAnimals
type Converter interface {
	Convert(source Input) Output

	// used only in extend method
	ConvertDogs([]Dog) []Animal
	ConvertCats([]Cat) []Animal
}

type Input struct {
	Animals InputAnimals
}
type InputAnimals struct {
	Cats []Cat
	Dogs []Dog
}
type Output struct {
	Animals []Animal
}

type Cat struct{ Name string }
type Dog struct{ Name string }

type Animal struct{ Name string }

func ConvertAnimals(c Converter, input InputAnimals) []Animal {
	dogs := c.ConvertDogs(input.Dogs)
	cats := c.ConvertCats(input.Cats)
	return append(dogs, cats...)
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import extendlocalwithconverter "github.com/jmattheis/goverter/example/extend-local-with-converter"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source extendlocalwithconverter.Input) extendlocalwithconverter.Output {
	var exampleOutput extendlocalwithconverter.Output
	exampleOutput.Animals = extendlocalwithconverter.ConvertAnimals(c, source.Animals)
	return exampleOutput
}
func (c *ConverterImpl) ConvertCats(source []extendlocalwithconverter.Cat) []extendlocalwithconverter.Animal {
	var exampleAnimalList []extendlocalwithconverter.Animal
	if source != nil {
		exampleAnimalList = make([]extendlocalwithconverter.Animal, len(source))
		for i := 0; i < len(source); i++ {
			exampleAnimalList[i] = c.exampleCatToExampleAnimal(source[i])
		}
	}
	return exampleAnimalList
}
func (c *ConverterImpl) ConvertDogs(source []extendlocalwithconverter.Dog) []extendlocalwithconverter.Animal {
	var exampleAnimalList []extendlocalwithconverter.Animal
	if source != nil {
		exampleAnimalList = make([]extendlocalwithconverter.Animal, len(source))
		for i := 0; i < len(source); i++ {
			exampleAnimalList[i] = c.exampleDogToExampleAnimal(source[i])
		}
	}
	return exampleAnimalList
}
func (c *ConverterImpl) exampleCatToExampleAnimal(source extendlocalwithconverter.Cat) extendlocalwithconverter.Animal {
	var exampleAnimal extendlocalwithconverter.Animal
	exampleAnimal.Name = source.Name
	return exampleAnimal
}
func (c *ConverterImpl) exampleDogToExampleAnimal(source extendlocalwithconverter.Dog) extendlocalwithconverter.Animal {
	var exampleAnimal extendlocalwithconverter.Animal
	exampleAnimal.Name = source.Name
	return exampleAnimal
}

Method with error

Sometimes, custom conversion may fail, in this case Goverter allows you to define a second return parameter which must of type error

go
func IntToString(i int) (string, error) {
    return "42", errors.new("oops something went wrong")
}
Example (click to expand)
go
package example

import "strconv"

// goverter:converter
// goverter:extend StringToInt
type Converter interface {
	Convert(Input) (Output, error)
}

type Input struct{ Value string }
type Output struct{ Value int }

func StringToInt(value string) (int, error) {
	i, err := strconv.Atoi(value)
	return i, err
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import extendwitherror "github.com/jmattheis/goverter/example/extend-with-error"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source extendwitherror.Input) (extendwitherror.Output, error) {
	var exampleOutput extendwitherror.Output
	xint, err := extendwitherror.StringToInt(source.Value)
	if err != nil {
		return exampleOutput, err
	}
	exampleOutput.Value = xint
	return exampleOutput, nil
}