Skip to content

Commit

Permalink
mapstruct#1799 Fluent setters starting with set should work properly
Browse files Browse the repository at this point in the history
  • Loading branch information
filiphr committed Sep 22, 2019
1 parent a71e7c0 commit 318b30e
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ else if ( isPresenceCheckMethod( method ) ) {
}

/**
* 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.
Expand All @@ -69,6 +70,10 @@ else if ( isPresenceCheckMethod( method ) ) {
* @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 &&
Expand Down Expand Up @@ -166,11 +171,22 @@ public boolean isPresenceCheckMethod(ExecutableElement method) {
@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 ) );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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" );
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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 );
}
}
}

0 comments on commit 318b30e

Please sign in to comment.