mapstruct – java processer plugin for mapping class attributes

Posted by

MapStruct is a Java annotation processor for the generation mapping classes, its good alternative for Dozer Mapper.

In this tutorial ew have tried as many possible example for more Info please refer to http://mapstruct.org/ (Mapstruct supports Java 6 and above)

– Define Mapper interface which declares required mapping method 

– During Compilation an implementation class will be generated for the Interface

– Implementation class will have mapping related code between source and target objects

Disadvantages

– Map Struct doesn’t support nested mappings (multi level attributes) on the Target Object 

Add below maven dependences and plugin 

<plugin>
	<groupId>org.bsc.maven</groupId>
	<artifactId>maven-processor-plugin</artifactId>
	<version>2.2.4</version>
	<configuration>
		<defaultOutputDirectory>
			${project.build.directory}/generated-sources
		</defaultOutputDirectory>
		<processors>
			<processor>org.mapstruct.ap.MappingProcessor</processor>
		</processors>
	</configuration>
	<executions>
		<execution>
			<id>process</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>process</goal>
			</goals>
		</execution>
	</executions>
	<dependencies>
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct-processor</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
	</dependencies>
</plugin>

<dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct-jdk8</artifactId>
	<version>1.1.0.Final</version>
</dependency>

MapStruct Examples : 

All examples shown here are written using below classes 

public class Source {

	private String sourceId;
	private List<SourceList> sourceList;
	private Customer customer;

	static class Customer {
		private String address;
	}

	static class SourceList {
		private Integer limit;
	}

}

public class Target {

	private String targetId;
	private List<TargetList> targetList;
	private String address;
	private Integer count;

	static class TargetList {
		private Integer targetLimit;
	}
}

1. Basic Mapper 

@Mapper
public interface MapStructMapper {

 @Mappings({ @Mapping(source = "sourceId", target = "targetId") })
 public Target getTarget(Source source);

}

Map Struct Generated Class :

@Component

public class MapStructMapperImpl implements MapStructMapper {

	@Override

	public Target getTarget(Source source) {

		if (source == null) {

			return null;
		}

		Target target = new Target();

		if (source.getSourceId() != null) {

			target.setTargetId(source.getSourceId());
		}

		return target;
	}
}

2. No mapping required if attribute names are same in both source and target.

3. Constants / Default Values

@Mapper
public interface MapStructMapper {

 @Mappings({ @Mapping(source = "sourceId", target = "targetId" , defaultValue="T1"), @Mapping(target = "constant", constant = "2000") })
 public Target getTarget(Source source);

}

Map Struct Generated Class :

public class MapStructMapperImpl implements MapStructMapper {

	@Override

	public Target getTarget(Source source) {

		if (source == null) {

			return null;
		}

		Target target = new Target();

		if (source.getSourceId() != null) {

			target.setTargetId(source.getSourceId());
		}

		else {

			target.setTargetId("T1");
		}

		target.setCount(Integer.parseInt("2000"));

		return target;
	}
}

4. Nested Mappings from Source class

@Mappings({ @Mapping(source = "customer.address", target = "address") })
 public Target getTarget(Source source);

Map Struct Generated Class :

public class MapStructMapperImpl implements MapStructMapper {

	@Override

	public Target getTarget(Source source) {

		if (source == null) {

			return null;
		}

		Target target = new Target();

		target.setAddress(sourceCustomerAddress(source));

		return target;
	}

	private String sourceCustomerAddress(Source source) {

		if (source == null) {

			return null;
		}

		Customer customer = source.getCustomer();

		if (customer == null) {

			return null;
		}

		String address = customer.getAddress();

		if (address == null) {

			return null;
		}

		return address;
	}
}

5. Enable Dependancy Injection by adding below in the Mapper Interface

@Mapper(componentModel = “spring")

6. Map List attributes (@IterableMapping)

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface MapStructMapper {

	@Mappings({ @Mapping(source = "customer.address", target = "address") })
	public Target getTarget(Source source);

	@IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
	public List< getParts(List<SourceList> component);

	@Mappings({ @Mapping(source = "limit", target = "targetLimit") })
	public TargetList getParts(SourceList sourceList);
}

Map Struct Generated Class :

@Component

public class MapStructMapperImpl implements MapStructMapper {

	@Override

	public Target getTarget(Source source) {

		if (source == null) {

			return null;
		}

		Target target = new Target();

		String customer = sourceCustomerAddress(source);

		if (customer != null) {

			target.setAddress(customer);
		}

		return target;
	}

	@Override

 public List&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;TargetList&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; getParts(List&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;SourceList&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; component) {

 if ( component == null ) {

 return new ArrayList&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;TargetList&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;();
 }

 List&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;TargetList&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; list = new ArrayList&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;TargetList&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;();

 for ( SourceList sourceList : component ) {

 list.add( getParts( sourceList ) );
 }

 return list;
 }

	@Override

	public TargetList getParts(SourceList sourceList) {

		if (sourceList == null) {

			return null;
		}

		TargetList targetList_ = new TargetList();

		if (sourceList.getLimit() != null) {

			targetList_.setTargetLimit(sourceList.getLimit());
		}

		return targetList_;
	}

	private String sourceCustomerAddress(Source source) {

		if (source == null) {

			return null;
		}

		Customer customer = source.getCustomer();

		if (customer == null) {

			return null;
		}

		String address = customer.getAddress();

		if (address == null) {

			return null;
		}

		return address;
	}
}

7. Map Struct will not include NULL check while mapping ,to add null check add below on the method or class level

nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface MapStructMapper {
Or
@IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)

 

Leave a Reply

Your email address will not be published.