/**
* 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.source;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.lang.model.element.ExecutableElement;
import org.mapstruct.ap.internal.model.common.Accessibility;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.util.MapperConfiguration;
import org.mapstruct.ap.internal.util.Strings;
/**
* This method will be generated in absence of a suitable abstract method to implement.
*
* @author Sjaak Derksen
*/
public class ForgedMethod implements Method {
private final List<Parameter> parameters;
private final Type returnType;
private final String name;
private final ExecutableElement positionHintElement;
private final List<Type> thrownTypes;
private final MapperConfiguration mapperConfiguration;
private final ForgedMethodHistory history;
private final List<Parameter> sourceParameters;
private final List<Parameter> contextParameters;
private final Parameter mappingTargetParameter;
private final MappingOptions mappingOptions;
private final ParameterProvidedMethods contextProvidedMethods;
private final boolean forgedNameBased;
/**
* Creates a new forged method with the given name.
*
* @param name the (unique name) for this method
* @param sourceType the source type
* @param returnType the return type.
* @param mapperConfiguration the mapper configuration
* @param positionHintElement element used to for reference to the position in the source file.
* @param additionalParameters additional parameters to add to the forged method
* @param parameterProvidedMethods additional factory/lifecycle methods to consider that are provided by context
* parameters
*/
public ForgedMethod(String name, Type sourceType, Type returnType, MapperConfiguration mapperConfiguration,
ExecutableElement positionHintElement, List<Parameter> additionalParameters,
ParameterProvidedMethods parameterProvidedMethods) {
this(
name,
sourceType,
returnType,
mapperConfiguration,
positionHintElement,
additionalParameters,
parameterProvidedMethods,
null,
null,
false );
}
/**
* Creates a new forged method with the given name.
*
* @param name the (unique name) for this method
* @param sourceType the source type
* @param returnType the return type.
* @param mapperConfiguration the mapper configuration
* @param positionHintElement element used to for reference to the position in the source file.
* @param additionalParameters additional parameters to add to the forged method
* @param parameterProvidedMethods additional factory/lifecycle methods to consider that are provided by context
* parameters
* @param history a parent forged method if this is a forged method within a forged method
* @param mappingOptions the mapping options for this method
* @param forgedNameBased forges a name based (matched) mapping method
*/
public ForgedMethod(String name, Type sourceType, Type returnType, MapperConfiguration mapperConfiguration,
ExecutableElement positionHintElement, List<Parameter> additionalParameters,
ParameterProvidedMethods parameterProvidedMethods, ForgedMethodHistory history,
MappingOptions mappingOptions, boolean forgedNameBased) {
String sourceParamName = Strings.decapitalize( sourceType.getName() );
String sourceParamSafeName = Strings.getSaveVariableName( sourceParamName );
this.parameters = new ArrayList<Parameter>( 1 + additionalParameters.size() );
Parameter sourceParameter = new Parameter( sourceParamSafeName, sourceType );
this.parameters.add( sourceParameter );
this.parameters.addAll( additionalParameters );
this.sourceParameters = Parameter.getSourceParameters( parameters );
this.contextParameters = Parameter.getContextParameters( parameters );
this.mappingTargetParameter = Parameter.getMappingTargetParameter( parameters );
this.contextProvidedMethods = parameterProvidedMethods;
this.returnType = returnType;
this.thrownTypes = new ArrayList<Type>();
this.name = Strings.sanitizeIdentifierName( name );
this.mapperConfiguration = mapperConfiguration;
this.positionHintElement = positionHintElement;
this.history = history;
this.mappingOptions = mappingOptions == null ? MappingOptions.empty() : mappingOptions;
this.mappingOptions.initWithParameter( sourceParameter );
this.forgedNameBased = forgedNameBased;
}
/**
* creates a new ForgedMethod with the same arguments but with a new name
* @param name the new name
* @param forgedMethod existing forge method
*/
public ForgedMethod(String name, ForgedMethod forgedMethod) {
this.parameters = forgedMethod.parameters;
this.returnType = forgedMethod.returnType;
this.thrownTypes = new ArrayList<Type>();
this.mapperConfiguration = forgedMethod.mapperConfiguration;
this.positionHintElement = forgedMethod.positionHintElement;
this.history = forgedMethod.history;
this.sourceParameters = Parameter.getSourceParameters( parameters );
this.contextParameters = Parameter.getContextParameters( parameters );
this.mappingTargetParameter = Parameter.getMappingTargetParameter( parameters );
this.mappingOptions = forgedMethod.mappingOptions;
this.contextProvidedMethods = forgedMethod.contextProvidedMethods;
this.name = name;
this.forgedNameBased = forgedMethod.forgedNameBased;
}
@Override
public boolean matches(List<Type> sourceTypes, Type targetType) {
if ( !targetType.equals( returnType ) ) {
return false;
}
if ( parameters.size() != sourceTypes.size() ) {
return false;
}
Iterator<Type> srcTypeIt = sourceTypes.iterator();
Iterator<Parameter> paramIt = parameters.iterator();
while ( srcTypeIt.hasNext() && paramIt.hasNext() ) {
Type sourceType = srcTypeIt.next();
Parameter param = paramIt.next();
if ( !sourceType.equals( param.getType() ) ) {
return false;
}
}
return true;
}
@Override
public Type getDeclaringMapper() {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public List<Parameter> getParameters() {
return parameters;
}
@Override
public List<Parameter> getSourceParameters() {
return sourceParameters;
}
@Override
public List<Parameter> getContextParameters() {
return contextParameters;
}
@Override
public ParameterProvidedMethods getContextProvidedMethods() {
return contextProvidedMethods;
}
@Override
public Parameter getMappingTargetParameter() {
return mappingTargetParameter;
}
@Override
public Parameter getTargetTypeParameter() {
return null;
}
@Override
public Accessibility getAccessibility() {
return Accessibility.PROTECTED;
}
@Override
public Type getReturnType() {
return returnType;
}
@Override
public List<Type> getThrownTypes() {
return thrownTypes;
}
public ForgedMethodHistory getHistory() {
return history;
}
public boolean isForgedNamedBased() {
return forgedNameBased;
}
public void addThrownTypes(List<Type> thrownTypesToAdd) {
for ( Type thrownType : thrownTypesToAdd ) {
// make sure there are no duplicates coming from the keyAssignment thrown types.
if ( !thrownTypes.contains( thrownType ) ) {
thrownTypes.add( thrownType );
}
}
}
@Override
public Type getResultType() {
return mappingTargetParameter != null ? mappingTargetParameter.getType() : returnType;
}
@Override
public List<String> getParameterNames() {
List<String> parameterNames = new ArrayList<String>();
for ( Parameter parameter : getParameters() ) {
parameterNames.add( parameter.getName() );
}
return parameterNames;
}
@Override
public boolean overridesMethod() {
return false;
}
@Override
public ExecutableElement getExecutable() {
return positionHintElement;
}
@Override
public boolean isLifecycleCallbackMethod() {
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder( returnType.toString() );
sb.append( " " );
sb.append( getName() ).append( "(" ).append( Strings.join( parameters, ", " ) ).append( ")" );
return sb.toString();
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isDefault() {
return false;
}
@Override
public Type getDefiningType() {
return null;
}
@Override
public MapperConfiguration getMapperConfiguration() {
return mapperConfiguration;
}
@Override
public boolean isUpdateMethod() {
return getMappingTargetParameter() != null;
}
/**
* object factory mechanism not supported for forged methods
*
* @return false
*/
@Override
public boolean isObjectFactory() {
return false;
}
@Override
public MappingOptions getMappingOptions() {
return mappingOptions;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ForgedMethod that = (ForgedMethod) o;
if ( parameters != null ? !parameters.equals( that.parameters ) : that.parameters != null ) {
return false;
}
return returnType != null ? returnType.equals( that.returnType ) : that.returnType == null;
}
@Override
public int hashCode() {
int result = parameters != null ? parameters.hashCode() : 0;
result = 31 * result + ( returnType != null ? returnType.hashCode() : 0 );
return result;
}
}