All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mapstruct.ap.internal.model.ContainerMappingMethodBuilder Maven / Gradle / Ivy

There is a newer version: 1.6.3
Show newest version
/**
 *  Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
 *  and/or other contributors as indicated by the @authors tag. See the
 *  copyright.txt file in the distribution for a full listing of all
 *  contributors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.mapstruct.ap.internal.model;

import static org.mapstruct.ap.internal.util.Collections.first;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
import org.mapstruct.ap.internal.util.Strings;

/**
 * Builder that can be used to build {@link ContainerMappingMethod}(s).
 *
 * @param  the builder itself that needs to be used for chaining
 * @param  the method that the builder builds
 *
 * @author Filip Hrisafov
 */
public abstract class ContainerMappingMethodBuilder,
    M extends ContainerMappingMethod> extends AbstractMappingMethodBuilder {

    private SelectionParameters selectionParameters;
    private FormattingParameters formattingParameters;
    private NullValueMappingStrategyPrism nullValueMappingStrategy;
    private String errorMessagePart;
    private String callingContextTargetPropertyName;

    ContainerMappingMethodBuilder(Class selfType, String errorMessagePart) {
        super( selfType );
        this.errorMessagePart = errorMessagePart;
    }

    public B formattingParameters(FormattingParameters formattingParameters) {
        this.formattingParameters = formattingParameters;
        return myself;
    }

    public B selectionParameters(SelectionParameters selectionParameters) {
        this.selectionParameters = selectionParameters;
        return myself;
    }

    public B nullValueMappingStrategy(NullValueMappingStrategyPrism nullValueMappingStrategy) {
        this.nullValueMappingStrategy = nullValueMappingStrategy;
        return myself;
    }

    public B callingContextTargetPropertyName(String callingContextTargetPropertyName) {
        this.callingContextTargetPropertyName = callingContextTargetPropertyName;
        return myself;
    }

    @Override
    public final M build() {
        Type sourceParameterType = first( method.getSourceParameters() ).getType();
        Type resultType = method.getResultType();

        Type sourceElementType = getElementType( sourceParameterType );
        Type targetElementType = getElementType( resultType );

        String loopVariableName =
            Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() );

        SourceRHS sourceRHS = new SourceRHS(
            loopVariableName,
            sourceElementType,
            new HashSet(),
            errorMessagePart
        );
        Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
            method,
            targetElementType,
            callingContextTargetPropertyName,
            formattingParameters,
            selectionParameters,
            sourceRHS,
            false
        );

        if ( assignment == null ) {
            assignment = forgeMapping( sourceRHS, sourceElementType, targetElementType );
        }
        else {
            if ( method instanceof ForgedMethod ) {
                ForgedMethod forgedMethod = (ForgedMethod) method;
                forgedMethod.addThrownTypes( assignment.getThrownTypes() );
            }
        }
        if ( assignment == null ) {
            if ( method instanceof ForgedMethod ) {
                // leave messaging to calling property mapping
                return null;
            }
            else {
                reportCannotCreateMapping(
                    method,
                    String.format( "%s \"%s\"", sourceRHS.getSourceErrorMessagePart(), sourceRHS.getSourceType() ),
                    sourceRHS.getSourceType(),
                    targetElementType,
                    ""
                );
            }
        }

        assignment = getWrapper( assignment, method );

        // mapNullToDefault
        boolean mapNullToDefault = false;
        if ( method.getMapperConfiguration() != null ) {
            mapNullToDefault = method.getMapperConfiguration().isMapToDefault( nullValueMappingStrategy );
        }

        MethodReference factoryMethod = null;
        if ( !method.isUpdateMethod() ) {
            factoryMethod = ctx.getMappingResolver().getFactoryMethod( method, method.getResultType(), null );
        }

        Set existingVariables = new HashSet( method.getParameterNames() );
        existingVariables.add( loopVariableName );

        List beforeMappingMethods = LifecycleCallbackFactory.beforeMappingMethods(
            method,
            selectionParameters,
            ctx,
            existingVariables
        );
        List afterMappingMethods = LifecycleCallbackFactory.afterMappingMethods(
            method,
            selectionParameters,
            ctx,
            existingVariables
        );

        return instantiateMappingMethod(
            method,
            existingVariables,
            assignment,
            factoryMethod,
            mapNullToDefault,
            loopVariableName,
            beforeMappingMethods,
            afterMappingMethods,
            selectionParameters
        );
    }

    protected abstract M instantiateMappingMethod(Method method, Collection existingVariables,
                                                  Assignment assignment, MethodReference factoryMethod,
                                                  boolean mapNullToDefault, String loopVariableName,
                                                  List beforeMappingMethods,
                                                  List afterMappingMethods,
        SelectionParameters selectionParameters);

    protected abstract Type getElementType(Type parameterType);

    protected abstract Assignment getWrapper(Assignment assignment, Method method);

    @Override
    protected boolean shouldUsePropertyNamesInHistory() {
        return false;
    }
}