Skip to content

Generate output into the same package

To output the generated implementation into the package containing the converter interface you can follow these steps:

Configure generation

Configure output to output the file into the same directory, define the full package path, and then run goverter gen.

go
package samepackage

// goverter:converter
// goverter:output:file ./generated.go
// goverter:output:package github.com/jmattheis/goverter/example/samepackage
type Converter interface {
	Convert(source *Input) *Output
}

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

package samepackage

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source *Input) *Output {
	var pSamepackageOutput *Output
	if source != nil {
		var samepackageOutput Output
		samepackageOutput.Name = (*source).Name
		pSamepackageOutput = &samepackageOutput
	}
	return pSamepackageOutput
}

Use implementation

Goverter will ignore files generated by goverter when generating the implementation. (See Build Constraint)

This means if you want to use the implementation in the same package e.g

go
package samepackage

import "errors"

func ValidateAndConvert(source *Input) (*Output, error) {
	if source.Name == "" {
		return nil, errors.New("Name may not be nil")
	}

	c := &ConverterImpl{}
	return c.Convert(source)
}

Goverter will fail with an complilation error like this:

could not load package github.com/jmattheis/goverter/example/samepackage

-: # github.com/jmattheis/goverter/example/samepackage
samepackage/use.go:12:8: undefined: ConverterImpl

Goverter cannot generate converters when there are compile errors because it
requires the type information from the compiled sources.

You can fix this by adding the Build Constraint to the newly added file like this:

go
//go:build !goverter

package samepackage

import "errors"

func ValidateAndConvert(source *Input) (*Output, error) {
	if source.Name == "" {
		return nil, errors.New("Name may not be nil")
	}

	c := &ConverterImpl{}
	output := c.Convert(source)
	return output, nil
}
go
package samepackage

// goverter:converter
// goverter:output:file ./generated.go
// goverter:output:package github.com/jmattheis/goverter/example/samepackage
type Converter interface {
	Convert(source *Input) *Output
}

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

package samepackage

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source *Input) *Output {
	var pSamepackageOutput *Output
	if source != nil {
		var samepackageOutput Output
		samepackageOutput.Name = (*source).Name
		pSamepackageOutput = &samepackageOutput
	}
	return pSamepackageOutput
}

or by defining a global variable with the type of the interface and then assigning it in a different file containing a Build Constraint.

go
package samepackage

import "errors"

var c Converter

func ValidateAndConvert2(source *Input) (*Output, error) {
	if source.Name == "" {
		return nil, errors.New("Name may not be nil")
	}

	output := c.Convert(source)
	return output, nil
}
go
//go:build !goverter

package samepackage

func init() {
	c = &ConverterImpl{}
}
go
package samepackage

// goverter:converter
// goverter:output:file ./generated.go
// goverter:output:package github.com/jmattheis/goverter/example/samepackage
type Converter interface {
	Convert(source *Input) *Output
}

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

package samepackage

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source *Input) *Output {
	var pSamepackageOutput *Output
	if source != nil {
		var samepackageOutput Output
		samepackageOutput.Name = (*source).Name
		pSamepackageOutput = &samepackageOutput
	}
	return pSamepackageOutput
}