/**
* 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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.SourceMethod;
import org.mapstruct.ap.internal.model.source.selector.MethodSelectors;
import org.mapstruct.ap.internal.model.source.selector.SelectedMethod;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
/**
* Factory for creating lists of appropriate {@link LifecycleCallbackMethodReference}s
*
* @author Andreas Gudian
*/
public final class LifecycleCallbackFactory {
private LifecycleCallbackFactory() {
}
/**
* @param method the method to obtain the beforeMapping methods for
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames the existing variable names in the mapping method
* @return all applicable {@code @BeforeMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> beforeMappingMethods(Method method,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods(
method,
selectionParameters,
filterBeforeMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
existingVariableNames );
}
/**
* @param method the method to obtain the afterMapping methods for
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames list of already used variable names
* @return all applicable {@code @AfterMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> afterMappingMethods(Method method,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods(
method,
selectionParameters,
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
existingVariableNames );
}
private static List<SourceMethod> getAllAvailableMethods(Method method, List<SourceMethod> sourceModelMethods) {
ParameterProvidedMethods contextProvidedMethods = method.getContextProvidedMethods();
if ( contextProvidedMethods.isEmpty() ) {
return sourceModelMethods;
}
List<SourceMethod> methodsProvidedByParams = contextProvidedMethods
.getAllProvidedMethodsInParameterOrder( method.getContextParameters() );
List<SourceMethod> availableMethods =
new ArrayList<SourceMethod>( methodsProvidedByParams.size() + sourceModelMethods.size() );
availableMethods.addAll( methodsProvidedByParams );
availableMethods.addAll( sourceModelMethods );
return availableMethods;
}
private static List<LifecycleCallbackMethodReference> collectLifecycleCallbackMethods(
Method method, SelectionParameters selectionParameters, List<SourceMethod> callbackMethods,
MappingBuilderContext ctx, Set<String> existingVariableNames) {
MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory() );
List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
method,
callbackMethods,
Collections.<Type> emptyList(),
method.getResultType(),
SelectionCriteria.forLifecycleMethods( selectionParameters ) );
return toLifecycleCallbackMethodRefs(
method,
matchingMethods,
ctx,
existingVariableNames );
}
private static List<LifecycleCallbackMethodReference> toLifecycleCallbackMethodRefs(Method method,
List<SelectedMethod<SourceMethod>> candidates,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
List<LifecycleCallbackMethodReference> result = new ArrayList<LifecycleCallbackMethodReference>();
for ( SelectedMethod<SourceMethod> candidate : candidates ) {
Parameter providingParameter =
method.getContextProvidedMethods().getParameterForProvidedMethod( candidate.getMethod() );
if ( providingParameter != null ) {
result.add( LifecycleCallbackMethodReference.forParameterProvidedMethod(
candidate,
providingParameter,
method,
existingVariableNames ) );
}
else {
MapperReference mapperReference = findMapperReference(
ctx.getMapperReferences(),
candidate.getMethod() );
result.add( LifecycleCallbackMethodReference.forMethodReference(
candidate,
mapperReference,
method,
existingVariableNames ) );
}
}
return result;
}
private static MapperReference findMapperReference(List<MapperReference> mapperReferences, SourceMethod method) {
for ( MapperReference ref : mapperReferences ) {
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
ref.setUsed( ref.isUsed() || !method.isStatic() );
ref.setTypeRequiresImport( true );
return ref;
}
}
return null;
}
private static List<SourceMethod> filterBeforeMappingMethods(List<SourceMethod> methods) {
List<SourceMethod> result = new ArrayList<SourceMethod>();
for ( SourceMethod method : methods ) {
if ( method.isBeforeMappingMethod() ) {
result.add( method );
}
}
return result;
}
private static List<SourceMethod> filterAfterMappingMethods(List<SourceMethod> methods) {
List<SourceMethod> result = new ArrayList<SourceMethod>();
for ( SourceMethod method : methods ) {
if ( method.isAfterMappingMethod() ) {
result.add( method );
}
}
return result;
}
}