Bernado
Bernado

Reputation: 628

Mapstruct 1.4.x - iterable to nonit. sample works strange with target dot operator

I want to adopt the sample from here

https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-iterable-to-non-iterable

with the difference to use the „.“ target operator instead of some nested property. Given the sample I want the „myString“ as result, so String would be the new Target.

But, using the dot operator nothing happens. Nothing happens means that mapstruct only creates a new instance of String without iterable to noniterable mapping. Is this a desired behavior?

As said here the example (adopted from the sample above):

@Mapper( uses = IterableNonInterableUtil.class )
public interface SourceTargetMapper {

    SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );

    //@Mapping( source = "myIntegers", target = "myInteger", qualifiedBy = FirstElement.class )
    @Mapping( source = "myStrings", target = ".", qualifiedBy = LastElement.class )
    String toTarget( Source s );
}
public class Main {

    private Main() {
    }

    public static void main( String[] args ) {
        Source s = new Source();
        s.setMyIntegers( Arrays.asList( 5, 3, 7 ) );
        s.setMyStrings( Arrays.asList( "five", "three", "seven " ) );

       // Target t = SourceTargetMapper.MAPPER.toTarget( s );
       // System.out.println( t.getMyInteger() );
        //System.out.println( t.getMyString() );
        String t = SourceTargetMapper.MAPPER.toTarget( s );
        System.out.println(t);
    }
}

Prints nothing as the generated code looks like:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-02-13T15:34:11+0100",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.5 (JetBrains s.r.o)"
)
public class SourceTargetMapperImpl implements SourceTargetMapper {

    @Override
    public String toTarget(Source s) {
        if ( s == null ) {
            return null;
        }

        String string = new String();

        return string;
    }
}

Other classes are left as they are.


Another example: Hi Filip, sorry for beeing late. I want to show you another use case that doesn't work for me or as i expected by using the "qualifiedBy"-atribute. What am i missing?

Class Address:

public class Address {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address(String name) {
        this.name = name;
    }

    private String name;

    @Override
    public String toString() {
        return "Address{" +
                "name='" + name + '\'' +
                '}';
    }
}

Class Customer with a list of addresses:

public class CustomerManyAddresses {

    public List<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }

    private List<Address> addresses;
}

the Mapper class:

@Mapper(uses = IterableNonInterableUtil.class)
public abstract class AddressMapper {

    @Mapping(target = ".", source = "addresses", qualifiedBy = FirstElement.class)
    abstract Address toSingle(CustomerManyAddresses customerManyAddresses);
}

and the test:

public class CustomerAddressMapperTest {

    private AddressMapper addressMapper = Mappers.getMapper(AddressMapper.class);

    @Test
    public void testCustomerMapper() {

        CustomerManyAddresses customerManyAddresses = new CustomerManyAddresses();
        Address address1 = new Address("first");
        Address address2 = new Address("second");
        Address address3 = new Address("third");
        customerManyAddresses.setAddresses(Arrays.asList(address1, address2, address3));

        Address singleAddress = addressMapper.toSingle(customerManyAddresses);
        System.out.println(singleAddress);
    }
}

...which only prints the new generated address, here no iterable to non-iter. is used again. the generated class:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-02-20T11:05:53+0100",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.5 (JetBrains s.r.o)"
)
public class AddressMapperImpl extends AddressMapper {

    @Override
    Address toSingle(CustomerManyAddresses customerManyAddresses) {
        if ( customerManyAddresses == null ) {
            return null;
        }

        String name = null;

        Address address = new Address( name );

        return address;
    }
}

Upvotes: 2

Views: 807

Answers (1)

Filip
Filip

Reputation: 21423

MapStruct does not allow mapping into a String. When you use target = "." you are saying that you want to map the properties of the first element into the properties of the target.

What you can do is to wrap the target string into a bean and then do the mapping like that.

What I would suggest though is to write your own custom method when you want to get only a String back.

Upvotes: 2

Related Questions