Unmapped target property due to use of @AfterMapping

2,600 views
Skip to first unread message

Ben Wimpory

unread,
Nov 4, 2016, 6:58:04 AM11/4/16
to mapstruct-users
Hi,

I am using a method with @AfterMapping annotation to map two "source" fields (a & b) from a DTO into a single field (x) on the target object.  This works.

Unfortunately due to a lack of @Mapping on the the two source fields (a&b) I get compilation warnings about these fields being unmapped.

Is my approach of using @AfterMapping on a custom method the right approach for doing a n->1 mapping ?

Thanks,

Ben

Gunnar Morling

unread,
Nov 4, 2016, 7:05:02 AM11/4/16
to Ben Wimpory, mapstruct-users
Hi ben,

That warning is about unmapped *target* properties, so you should not see it about unmapped source fields. The rationale being that a mapping can be considered as a projection and it's legit to only have a subset of the source properties in a given target (e.g. for a view DTO), whereas an unpopulated property in the returned object is suspicious. 

Could you double check whether that's indeed about source properties? In that case could you provide a complete example exposing this issue?

>  Is my approach of using @AfterMapping on a custom method the right approach

You can do that, or go for an expression, which probably is less effort: @Mapping(target="x", expression="java(source.getA() + source.getB())"

Finally, You also can use @Mapping#ignore() and @Mapper#unmappedTargetPropertyPolicy() to get rid of the warning, but I'd double check first whether everything is doing what it should be doing.

--Gunnar


--Gunnar


--
You received this message because you are subscribed to the Google Groups "mapstruct-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mapstruct-users+unsubscribe@googlegroups.com.
To post to this group, send email to mapstruct-users@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ben Wimpory

unread,
Nov 22, 2016, 1:14:40 PM11/22/16
to mapstruct-users, benwi...@gmail.com, gun...@hibernate.org
Apologies for the delay getting back to you on this.

The error I am seeing from the example code below is about an unmapped target property.  This is created as I have only partially mapped the fields in the mapper, leaving the mapping of two source fields into one target field to an @AfterMapping.

:compileTestJava
...../src/test/java/mapstruct/InternalMapper.java:14: warning: Unmapped target property: "fullName".
    Internal internalFromDTO(DTO dto);
             ^


package mapstruct;

class DTO {
private int age;
private String first;
private String last;

public DTO(int age, String first, String last) {
this.age = age;
this.first = first;
this.last = last;
}

public int getAge() {
return age;
}

public String getFirst() {
return first;
}

public String getLast() {
return last;
}
}

package mapstruct;

class Internal
{
private int ageInYears;
private String fullName;

public Internal() {
}

public void setAgeInYears(int ageInYears) {
this.ageInYears = ageInYears;
}

public void setFullName(String fullName) {
this.fullName = fullName;
}

public int getAgeInYears() {
return ageInYears;
}

public String getFullName() {
return fullName;
}
}

package mapstruct;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

@Mapper(uses = NameMapper.class)
public interface InternalMapper {
@Mappings(
{
@Mapping(source = "age", target = "ageInYears")
}
)
Internal internalFromDTO(DTO dto);

}

package mapstruct;

import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;

@Mapper
public abstract class NameMapper {
@AfterMapping
void after(DTO dto, @MappingTarget Internal internal)
{
internal.setFullName(String.format("%s, %s", dto.getLast(), dto.getFirst()));
}
}


package mapstruct;

import org.junit.Test;
import org.mapstruct.factory.Mappers;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

/**
* Generates warning about unmapped target field, but have used @AfterMapping to set this field
* .../src/test/java/mapstruct/InternalMapper.java:14: warning: Unmapped target property: "fullName".
Internal internalFromDTO(DTO dto);
^
*/
public class UnusedSourceFieldsTests {

@Test
public void causesUnusedSourceFieldWarnings()
{
final InternalMapper mapper = Mappers.getMapper(InternalMapper.class);
final DTO dto = new DTO(20, "Wish", "iWas");
final Internal internal = mapper.internalFromDTO(dto);

assertThat(internal.getFullName(), is("iWas, Wish"));
}

}
To unsubscribe from this group and stop receiving emails from it, send an email to mapstruct-use...@googlegroups.com.
To post to this group, send email to mapstru...@googlegroups.com.

Andreas Gudian

unread,
Nov 22, 2016, 1:21:18 PM11/22/16
to Ben Wimpory, mapstruct-users, gun...@hibernate.org
Hi Ben,

You can acknowledge the warning by explicitly adding @Mapping(target="fullName", ignore = true).

Andreas

Ben Wimpory

unread,
Nov 22, 2016, 1:36:00 PM11/22/16
to mapstruct-users, benwi...@gmail.com, gun...@hibernate.org
Agreed this removes the warning.  Many thanks.

Is this the recommended way to map two fields to one ?

package mapstruct;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

@Mapper(uses = NameMapper.class)
public interface InternalMapper {
@Mappings(
{
                    @Mapping(source = "age", target = "ageInYears"),

@Mapping(target="fullName", ignore = true)
}
    )
Internal internalFromDTO(DTO dto);

}

Andreas Gudian

unread,
Nov 22, 2016, 1:52:15 PM11/22/16
to Ben Wimpory, mapstruct-users, gun...@hibernate.org
Yes. Either that or using the 'expression' attribute in the @Mapping annotation - but personally I would do it with @AfterMapping as well.

Ben Wimpory

unread,
Nov 22, 2016, 1:55:09 PM11/22/16
to mapstruct-users
Ok - thanks. Great library btw :-)
Reply all
Reply to author
Forward
0 new messages