Skip to content

Two different constants are ignored #3673

@jacobbetz

Description

@jacobbetz

Expected behavior

I have this mapping defined

    @Mapping(target = "details.name", source = "details.name")
    @Mapping(target = "details.type", constant = "DOG")
    Animal map(Dog dog);

    @Mapping(target = "details.name", source = "details.name")
    @Mapping(target = "details.type", constant = "CAT")
    Animal map(Cat cat);

I would expect, that the field details.type is set dependent on the source object.

Actual behavior

I have definied this test

class AnimalMapperTest {

    @Test
    void mapCat() {
        Cat cat = new Cat(new Details("cat"));
        Animal animal = AnimalMapper.INSTANCE.map(cat);
        assertEquals(AnimalDetails.Type.CAT, animal.getDetails().getType());
        assertEquals(cat.getDetails().getName(), animal.getDetails().getName());
    }

    @Test
    void mapDog() {
        Dog dog = new Dog(new Details("cat"));
        Animal animal = AnimalMapper.INSTANCE.map(dog);
        assertEquals(AnimalDetails.Type.DOG, animal.getDetails().getType());
        assertEquals(dog.getDetails().getName(), animal.getDetails().getName());
    }

}

There, I get this exception:

org.opentest4j.AssertionFailedError: 
Expected :CAT
Actual   :DOG
<Click to see difference>

This is because mapstruct uses this method
animal.setDetails( detailsToAnimalDetails( dog.getDetails() ) );

    protected AnimalDetails detailsToAnimalDetails(Details details) {
        if ( details == null ) {
            return null;
        }

        AnimalDetails animalDetails = new AnimalDetails();

        animalDetails.setName( details.getName() );

        animalDetails.setType( AnimalDetails.Type.DOG );

        return animalDetails;
    }

And there, it does not distinguish between Dog and Cat.

With the version 1.5.5.Final this mapping did not fail.

Steps to reproduce the problem

import lombok.Data;

@Data
public class Animal {

    private AnimalDetails details;


}
import lombok.Data;

@Data
public class AnimalDetails {
    private Type type;
    private String name;

    public enum Type {
        CAT,
        DOG
    }

}
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface AnimalMapper {

    AnimalMapper INSTANCE = Mappers.getMapper(AnimalMapper.class);

    @Mapping(target = "details.name", source = "details.name")
    @Mapping(target = "details.type", constant = "DOG")
    Animal map(Dog dog);

    @Mapping(target = "details.name", source = "details.name")
    @Mapping(target = "details.type", constant = "CAT")
    Animal map(Cat cat);
}
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class AnimalMapperTest {

    @Test
    void mapCat() {
        Cat cat = new Cat(new Details("cat"));
        Animal animal = AnimalMapper.INSTANCE.map(cat);
        assertEquals(AnimalDetails.Type.CAT, animal.getDetails().getType());
        assertEquals(cat.getDetails().getName(), animal.getDetails().getName());
    }

    @Test
    void mapDog() {
        Dog dog = new Dog(new Details("cat"));
        Animal animal = AnimalMapper.INSTANCE.map(dog);
        assertEquals(AnimalDetails.Type.DOG, animal.getDetails().getType());
        assertEquals(dog.getDetails().getName(), animal.getDetails().getName());
    }

}
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Cat {

    Details details;
}

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Details {
    String name;
}
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Dog {

        Details details;
}

MapStruct Version

1.6.0

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions