/** * 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.builtin; import static org.mapstruct.ap.internal.util.Collections.first; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; import javax.lang.model.element.ExecutableElement; import org.mapstruct.ap.internal.conversion.SimpleConversion; import org.mapstruct.ap.internal.model.common.Accessibility; import org.mapstruct.ap.internal.model.common.ConversionContext; import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.source.MappingOptions; import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods; import org.mapstruct.ap.internal.util.MapperConfiguration; import org.mapstruct.ap.internal.util.Strings; /** * Represents a "built-in" mapping method which will be added as private method to the generated mapper. Built-in * methods are used in cases where a {@link SimpleConversion} doesn't suffice, e.g. as several lines of source code or a * try/catch block are required. * * @author Sjaak Derksen */ public abstract class BuiltInMethod implements Method { /** * {@inheritDoc } * * @return default method name is equal to class name of build in method name */ @Override public String getName() { return Strings.decapitalize( this.getClass().getSimpleName() ); } /** * Returns the types used by this method for which import statements need to be generated. Defaults to the empty * set. To be overridden by implementations in case they make use of additional types (note that the parameter and * return type don't need to be added). * * @return the types used by this method for which import statements need to be generated */ public Set<Type> getImportTypes() { return Collections.<Type>emptySet(); } /** * {@inheritDoc} * <p> * Default the targetType should be assignable to the returnType and the sourceType to the parameter, * excluding generic type variables. When the implementor sees a need for this, this method can be overridden. */ @Override public boolean matches(List<Type> sourceTypes, Type targetType) { if ( sourceTypes.size() != 1 ) { return false; } Type sourceType = first( sourceTypes ); if ( getReturnType().isAssignableTo( targetType.erasure() ) && sourceType.erasure().isAssignableTo( getParameter().getType() ) ) { return doTypeVarsMatch( sourceType, targetType ); } if ( getReturnType().getFullyQualifiedName().equals( "java.lang.Object" ) && sourceType.erasure().isAssignableTo( getParameter().getType() ) ) { // return type could be a type parameter T return doTypeVarsMatch( sourceType, targetType ); } if ( getReturnType().isAssignableTo( targetType.erasure() ) && getParameter().getType().getFullyQualifiedName().equals( "java.lang.Object" ) ) { // parameter type could be a type parameter T return doTypeVarsMatch( sourceType, targetType ); } return false; } @Override public List<Parameter> getSourceParameters() { return getParameters(); } @Override public List<Parameter> getContextParameters() { return Collections.emptyList(); } @Override public ParameterProvidedMethods getContextProvidedMethods() { return ParameterProvidedMethods.empty(); } /** * {@inheritDoc} * <p> * For built-in methods, the declaring mapper is always {@code null} as they will be added as private methods to the * generated mapper. * * @return {@code null} */ @Override public final Type getDeclaringMapper() { return null; } @Override public List<Parameter> getParameters() { return Arrays.asList( getParameter() ); } /** * mapping target parameter mechanism not supported for built-in methods * * @return {@code null} */ @Override public Parameter getMappingTargetParameter() { return null; } /** * target type parameter mechanism not supported for built-in methods * * @return {@code null} */ @Override public Parameter getTargetTypeParameter() { return null; } /** * object factory mechanism not supported for built-in methods * * @return false */ @Override public boolean isObjectFactory() { return false; } /** * the conversion context is used to format an auxiliary parameter in the method call with context specific * information such as a date format. * * @param conversionContext context * @return null if no context parameter should be included "null" if there should be an explicit null call * "'dateFormat'" for instance, to indicate how the build-in method should format the date */ public String getContextParameter(ConversionContext conversionContext) { return null; } /** * hashCode based on class * * @return hashCode */ @Override public int hashCode() { return this.getClass().hashCode(); } /** * equals based on class * * @param obj other class * * @return true when classes are the same */ @Override public boolean equals(Object obj) { if ( obj == null ) { return false; } return ( getClass() == obj.getClass() ); } /** * Analyzes the Java Generic type variables in the parameter do match the type variables in the build in method same * goes for the returnType. * * @param parameter source * @param returnType target * @return {@code true}, iff the the type variables match */ public boolean doTypeVarsMatch(Type parameter, Type returnType) { return true; } /** * There's currently only one parameter foreseen instead of a list of parameter * * @return the parameter */ public abstract Parameter getParameter(); @Override public Accessibility getAccessibility() { return Accessibility.PRIVATE; } @Override public List<Type> getThrownTypes() { return Collections.emptyList(); } @Override public Type getResultType() { return getReturnType(); } @Override public List<String> getParameterNames() { List<String> parameterNames = new ArrayList<String>( getParameters().size() ); for ( Parameter parameter : getParameters() ) { parameterNames.add( parameter.getName() ); } return parameterNames; } @Override public boolean overridesMethod() { return false; } @Override public ExecutableElement getExecutable() { return null; } @Override public boolean isStatic() { return false; } @Override public boolean isDefault() { return false; } @Override public Type getDefiningType() { return null; } @Override public MapperConfiguration getMapperConfiguration() { return null; } @Override public boolean isLifecycleCallbackMethod() { return false; } @Override public boolean isUpdateMethod() { return getMappingTargetParameter() != null; } @Override public MappingOptions getMappingOptions() { return MappingOptions.empty(); } }