Skip to content

Two different constants are ignored #3673

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions