Mapping an object to an immutable object with builder (using immutables annotation processor) in mapstruct

We had same issue on our project. As workaround we've been using Modifiable implementation of our immutable dto.

You can also try it. It's better that direct usage of builders and object factories.

@Value.Modifiable generates implementation with setters.

@Value.Style(create = "new") generates public no args constructor.

@Value.Immutable
@Value.Modifiable
@Value.Style(create = "new")
public interface MammalEntity {
    public Long getNumberOfLegs();
    public Long getNumberOfStomachs();
}

Then your mapper will be simpler, no need in object factory.

@Mapper
public interface SourceTargetMapper {

  ModifiableMammalEntity toTarget(MammalDto source);
}

In this case MapStruct can see setters in ModifiableMammalEntity

Usage of such mapper will looks like

// Here you don't need to worry about implementation of MammalEntity is. The interface `MammalEntity` is immutable.
MammalEntity mammalEntity = sourceTargetMapper.toTarget(source);

You can configure Immutables to generate setters in the builder:

@Value.Immutable
@Value.Style(init = "set*")
public interface MammalEntity {
    public Long getNumberOfLegs();
    public Long getNumberOfStomachs();
}

And you don't need the ObjectBuilder, you can directly use the generated Immutable class

@Mapper(uses = ImmutableMammalEntity.class)
public interface SourceTargetMapper {
    SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );

    ImmutableMammalEntity.Builder toTarget(MammalDto source);
}

You can even define these settings in your own annotation

@Value.Style(init = "set*")
public @interface SharedData {}

and use that instead

@SharedData
@Value.Immutable
public interface MammalEntity {
    public Long getNumberOfLegs();
    public Long getNumberOfStomachs();
}

Since 1.3 MapStruct supports Immutables. Look here for more details.