#1799 Fluent setters starting with set should work properly

This commit is contained in:
Filip Hrisafov 2019-09-22 18:22:11 +02:00
parent a71e7c0a0b
commit 318b30ef23
5 changed files with 163 additions and 6 deletions

View File

@ -57,7 +57,8 @@ public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
}
/**
* Returns {@code true} when the {@link ExecutableElement} is a getter method. A method is a getter when it starts
* Returns {@code true} when the {@link ExecutableElement} is a getter method. A method is a getter when it
* has no parameters, 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.
@ -69,6 +70,10 @@ public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
* @return {@code true} when the method is a getter.
*/
public boolean isGetterMethod(ExecutableElement method) {
if ( !method.getParameters().isEmpty() ) {
// If the method has parameters it can't be a getter
return false;
}
String methodName = method.getSimpleName().toString();
boolean isNonBooleanGetterName = methodName.startsWith( "get" ) && methodName.length() > 3 &&
@ -166,11 +171,22 @@ public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
@Override
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
String methodName = getterOrSetterMethod.getSimpleName().toString();
if ( methodName.startsWith( "get" ) || methodName.startsWith( "set" ) ) {
return IntrospectorUtils.decapitalize( methodName.substring( 3 ) );
}
else if ( isFluentSetter( getterOrSetterMethod ) ) {
return methodName;
if ( isFluentSetter( getterOrSetterMethod ) ) {
// If this is a fluent setter that starts with set and the 4th character is an uppercase one
// then we treat it as a Java Bean style method (we get the property starting from the 4th character).
// Otherwise we treat it as a fluent setter
// For example, for the following methods:
// * public Builder setSettlementDate(String settlementDate)
// * public Builder settlementDate(String settlementDate)
// We are going to extract the same property name settlementDate
if ( methodName.startsWith( "set" )
&& methodName.length() > 3
&& Character.isUpperCase( methodName.charAt( 3 ) ) ) {
return IntrospectorUtils.decapitalize( methodName.substring( 3 ) );
}
else {
return methodName;
}
}
return IntrospectorUtils.decapitalize( methodName.substring( methodName.startsWith( "is" ) ? 2 : 3 ) );
}

View File

@ -0,0 +1,20 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1799;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper
public interface Issue1799Mapper {
Issue1799Mapper INSTANCE = Mappers.getMapper( Issue1799Mapper.class );
Target map(Source source);
}

View File

@ -0,0 +1,37 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1799;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Filip Hrisafov
*/
@WithClasses({
Issue1799Mapper.class,
Source.class,
Target.class,
})
@IssueKey("1799")
@RunWith(AnnotationProcessorTestRunner.class)
public class Issue1799Test {
@Test
public void fluentJavaBeanStyleSettersShouldWork() {
Target target = Issue1799Mapper.INSTANCE.map( new Source( new Date( 150 ), "Switzerland" ) );
assertThat( target.getSettlementDate() ).isEqualTo( new Date( 150 ) );
assertThat( target.getGetawayLocation() ).isEqualTo( "Switzerland" );
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1799;
import java.util.Date;
/**
* @author Filip Hrisafov
*/
public class Source {
private final Date settlementDate;
private final String getawayLocation;
public Source(Date settlementDate, String getawayLocation) {
this.settlementDate = settlementDate;
this.getawayLocation = getawayLocation;
}
public Date getSettlementDate() {
return settlementDate;
}
public String getGetawayLocation() {
return getawayLocation;
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1799;
import java.util.Date;
/**
* @author Filip Hrisafov
*/
public class Target {
private final Date settlementDate;
private final String getawayLocation;
public Target(Builder builder) {
this.settlementDate = builder.settlementDate;
this.getawayLocation = builder.getawayLocation;
}
public Date getSettlementDate() {
return settlementDate;
}
public String getGetawayLocation() {
return getawayLocation;
}
public static Target.Builder builder() {
return new Builder();
}
public static class Builder {
private Date settlementDate;
private String getawayLocation;
public Builder settlementDate(Date settlementDate) {
this.settlementDate = settlementDate;
return this;
}
public Builder getawayLocation(String getawayLocation) {
this.getawayLocation = getawayLocation;
return this;
}
public Target build() {
return new Target( this );
}
}
}