org.mapstruct.ap.spi.DefaultAccessorNamingStrategy Maven / Gradle / Ivy
/**
* 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.spi;
import java.beans.Introspector;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleElementVisitor6;
import javax.lang.model.util.SimpleTypeVisitor6;
/**
* The default JavaBeans-compliant implementation of the {@link AccessorNamingStrategy} service provider interface.
*
* @author Christian Schuster, Sjaak Derken
*/
public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
@Override
public MethodType getMethodType(ExecutableElement method) {
if ( isGetterMethod( method ) ) {
return MethodType.GETTER;
}
else if ( isSetterMethod( method ) ) {
return MethodType.SETTER;
}
else if ( isAdderMethod( method ) ) {
return MethodType.ADDER;
}
else if ( isPresenceCheckMethod( method ) ) {
return MethodType.PRESENCE_CHECKER;
}
else {
return MethodType.OTHER;
}
}
/**
* Returns {@code true} when the {@link ExecutableElement} is a getter method. A method is a getter when it starts
* with 'get' and the return type is any type other than {@code void}, OR the getter starts with 'is' and the type
* returned is a primitive or the wrapper for {@code boolean}. NOTE: the latter does strictly not comply to the bean
* convention. The remainder of the name is supposed to reflect the property name.
*
* The calling MapStruct code guarantees that the given method has no arguments.
*
* @param method to be analyzed
*
* @return {@code true} when the method is a getter.
*/
public boolean isGetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
boolean isNonBooleanGetterName = methodName.startsWith( "get" ) && methodName.length() > 3 &&
method.getReturnType().getKind() != TypeKind.VOID;
boolean isBooleanGetterName = methodName.startsWith( "is" ) && methodName.length() > 2;
boolean returnTypeIsBoolean = method.getReturnType().getKind() == TypeKind.BOOLEAN ||
"java.lang.Boolean".equals( getQualifiedName( method.getReturnType() ) );
return isNonBooleanGetterName || ( isBooleanGetterName && returnTypeIsBoolean );
}
/**
* Returns {@code true} when the {@link ExecutableElement} is a setter method. A setter starts with 'set'. The
* remainder of the name is supposed to reflect the property name.
*
* The calling MapStruct code guarantees that there's only one argument.
*
* @param method to be analyzed
* @return {@code true} when the method is a setter.
*/
public boolean isSetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return methodName.startsWith( "set" ) && methodName.length() > 3;
}
/**
* Returns {@code true} when the {@link ExecutableElement} is an adder method. An adder method starts with 'add'.
* The remainder of the name is supposed to reflect the singular property name (as opposed to plural) of
* its corresponding property. For example: property "children", but "addChild". See also
* {@link #getElementName(ExecutableElement) }.
*
* The calling MapStruct code guarantees there's only one argument.
*
*
* @param method to be analyzed
*
* @return {@code true} when the method is an adder method.
*/
public boolean isAdderMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return methodName.startsWith( "add" ) && methodName.length() > 3;
}
/**
* Returns {@code true} when the {@link ExecutableElement} is a presence check method that checks if the
* corresponding property is present (e.g. not null, not nil, ..). A presence check method method starts with
* 'has'. The remainder of the name is supposed to reflect the property name.
*
* The calling MapStruct code guarantees there's no argument and that the return type is boolean or a
* {@link Boolean}
*
* @param method to be analyzed
* @return {@code true} when the method is a presence check method.
*/
public boolean isPresenceCheckMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return methodName.startsWith( "has" ) && methodName.length() > 3;
}
/**
* Analyzes the method (getter or setter) and derives the property name.
* See {@link #isGetterMethod(ExecutableElement)} {@link #isSetterMethod(ExecutableElement)}. The first three
* ('get' / 'set' scenario) characters are removed from the simple name, or the first 2 characters ('is' scenario).
* From the remainder the first character is made into small case (to counter camel casing) and the result forms
* the property name.
*
* @param getterOrSetterMethod getter or setter method.
*
* @return the property name.
*/
@Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
String methodName = getterOrSetterMethod.getSimpleName().toString();
return Introspector.decapitalize( methodName.substring( methodName.startsWith( "is" ) ? 2 : 3 ) );
}
/**
* Adder methods are used to add elements to collections on a target bean. A typical use case is JPA. The
* convention is that the element name will be equal to the remainder of the add method. Example: 'addElement'
* element name will be 'element'.
*
* @param adderMethod getter or setter method.
*
* @return the property name.
*/
@Override
public String getElementName(ExecutableElement adderMethod) {
String methodName = adderMethod.getSimpleName().toString();
return Introspector.decapitalize( methodName.substring( 3 ) );
}
/**
* Helper method, to obtain the fully qualified name of a type.
*
* @param type input type
*
* @return fully qualified name of type when the type is a {@link DeclaredType}, null when otherwise.
*/
protected static String getQualifiedName(TypeMirror type) {
DeclaredType declaredType = type.accept(
new SimpleTypeVisitor6() {
@Override
public DeclaredType visitDeclared(DeclaredType t, Void p) {
return t;
}
},
null
);
if ( declaredType == null ) {
return null;
}
TypeElement typeElement = declaredType.asElement().accept(
new SimpleElementVisitor6() {
@Override
public TypeElement visitType(TypeElement e, Void p) {
return e;
}
},
null
);
return typeElement != null ? typeElement.getQualifiedName().toString() : null;
}
@Override
public String getCollectionGetterName(String property) {
throw new IllegalStateException( "This method is not intended to be called anymore and will be removed in "
+ "future versions." );
}
}