Package org.mapstruct

Annotation Type Context


@Target(PARAMETER) @Retention(CLASS) public @interface Context
Marks a parameter of a method to be treated as mapping context. Such parameters are passed to other mapping methods, @ObjectFactory methods or @BeforeMapping/@AfterMapping methods when applicable and can thus be used in custom code.

The type of an @Context parameter is also inspected for @BeforeMapping/@AfterMapping methods, which are called on the provided context parameter value if applicable.

Note: no null checks are performed before calling before/after mapping methods or object factory methods on @Context annotated parameters. The caller needs to make sure that no null are passed in that case.

For generated code to call a method that is declared with @Context parameters, the declaration of the mapping method being generated needs to contain at least those (or assignable) @Context parameters as well. MapStruct will not create new instances of missing @Context parameters nor will it pass null instead.

Example 1: Using @Context parameters for passing data down to hand-written property mapping methods and @BeforeMapping methods:

 
 // multiple @Context parameters can be added
 public abstract CarDto toCar(Car car, @Context VehicleRegistration context, @Context Locale localeToUse);

 protected OwnerManualDto translateOwnerManual(OwnerManual ownerManual, @Context Locale locale) {
     // manually implemented logic to translate the OwnerManual with the given Locale
 }

 @BeforeMapping
 protected void registerVehicle(Vehicle mappedVehicle, @Context VehicleRegistration context) {
     context.register( mappedVehicle );
 }

 @BeforeMapping
 protected void notCalled(Vehicle mappedVehicle, @Context DifferentMappingContextType context) {
     // not called, because no context parameter of type DifferentMappingContextType is available
     // within toCar(Car, VehicleRegistration, Locale)
 }

 // generates:

 public CarDto toCar(Car car, VehicleRegistration context, Locale localeToUse) {
     registerVehicle( car, context );

     if ( car == null ) {
         return null;
     }

     CarDto carDto = new CarDto();

     carDto.setOwnerManual( translateOwnerManual( car.getOwnerManual(), localeToUse );
     // more generated mapping code

     return carDto;
 }
 
 

Example 2: Using an @Context parameter with a type that provides its own @ BeforeMapping methods to handle cycles in Graph structures:

 
 // type of the context parameter
 public class CyclicGraphContext {
     private Map<Object, Object> knownInstances = new IdentityHashMap<>();

     @BeforeMapping
     public <T extends NodeDto> T getMappedInstance(Object source, @TargetType Class<T> targetType) {
         return (T) knownInstances.get( source );
     }

     @BeforeMapping
     public void storeMappedInstance(Object source, @MappingTarget NodeDto target) {
         knownInstances.put( source, target );
     }
 }

 @Mapper
 public interface GraphMapper {
     NodeDto toNodeDto(Node node, @Context CyclicGraphContext cycleContext);
 }


 // generates:

 public NodeDto toNodeDto(Node node, CyclicGraphContext cycleContext) {
     NodeDto target = cycleContext.getMappedInstance( node, NodeDto.class );
     if ( target != null ) {
         return target;
     }

     if ( node == null ) {
         return null;
     }

     NodeDto nodeDto = new NodeDto();

     cycleContext.storeMappedInstance( node, nodeDto );

     nodeDto.setParent( toNodeDto( node.getParent(), cycleContext ) );
     List<NodeDto> list = nodeListToNodeDtoList( node.getChildren(), cycleContext );
     if ( list != null ) {
         nodeDto.setChildren( list );
     }

     // more mapping code

     return nodeDto;
 }
 
 

Example 3: Using @Context parameters for creating an entity object by calling an @ObjectFactory methods:

 
 // type of the context parameter
 public class ContextObjectFactory {
     @PersistenceContext(unitName = "my-unit")
     private EntityManager em;

     @ObjectFactory
     public Valve create( String id ) {
        Query query = em.createNamedQuery("Valve.findById");
        query.setParameter("id", id);
        Valve result = query.getSingleResult();
        if ( result != null ) {
            result = new Valve( id );
        }
        return result;
     }

 }

 @Mapper
 public interface ContextWithObjectFactoryMapper {
     Valve map(ValveDto dto, @Context ContextObjectFactory factory, String id);
 }


 // generates:
 public class ContextWithObjectFactoryMapperImpl implements ContextWithObjectFactoryMapper {

   @Override
   public Valve map(ValveDto dto, ContextObjectFactory factory, String id) {
       if ( dto == null ) {
           return null;
       }

       Valve valve = factory.create( id );

       valve.setOneWay( dto.isOneWay() );

       return valve;
   }
 }
 
 
Since:
1.2
Author:
Andreas Gudian