Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
*/
package org.mapstruct.ap.spi;

import java.util.List;
import java.util.regex.Pattern;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor6;
import javax.lang.model.util.SimpleTypeVisitor6;
Expand Down Expand Up @@ -102,10 +106,48 @@ public boolean isSetterMethod(ExecutableElement method) {
}

protected boolean isFluentSetter(ExecutableElement method) {
TypeMirror returnType = method.getReturnType();
Element enclosingElement = method.getEnclosingElement();

TypeElement enclosingTypeElement = (TypeElement) enclosingElement;

if ( returnType.getKind() == TypeKind.TYPEVAR
&& isTypeVariableRepresentingBuilder( returnType, enclosingTypeElement ) ) {
returnType = enclosingTypeElement.asType();
}

return method.getParameters().size() == 1 &&
!JAVA_JAVAX_PACKAGE.matcher( method.getEnclosingElement().asType().toString() ).matches() &&
!JAVA_JAVAX_PACKAGE.matcher( enclosingElement.asType().toString() ).matches() &&
!isAdderWithUpperCase4thCharacter( method ) &&
typeUtils.isAssignable( method.getReturnType(), method.getEnclosingElement().asType() );
typeUtils.isAssignable( returnType, enclosingElement.asType() );
}

private boolean isTypeVariableRepresentingBuilder(TypeMirror typeVariable, TypeElement builderElement) {
if ( typeVariable.getKind() != TypeKind.TYPEVAR ) {
return false;
}

String typeVarName = ((TypeVariable) typeVariable).asElement().getSimpleName().toString();

TypeElement currentElement = builderElement;
while ( currentElement != null ) {
List<? extends TypeParameterElement> typeParameters = currentElement.getTypeParameters();

for ( TypeParameterElement typeParam : typeParameters ) {
if ( typeParam.getSimpleName().contentEquals( typeVarName ) ) {
return true;
}
}

TypeMirror superclass = currentElement.getSuperclass();
if ( superclass.getKind() == TypeKind.NONE
|| superclass.toString().equals( Object.class.getCanonicalName() ) ) {
break;
}
currentElement = (TypeElement) ( (DeclaredType) superclass ).asElement();
}

return false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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._3707;

public abstract class AbstractDto {
private final String name;
private final Integer id;

public abstract static class Builder<T> {
private String name;
private Integer id;

protected abstract T self();

public T name(String name) {
this.name = name;
return self();
}

public T id(Integer id) {
this.id = id;
return self();
}

public abstract AbstractDto build();
}

protected AbstractDto(Builder<?> builder) {
this.name = builder.name;
this.id = builder.id;
}

public String getName() {
return name;
}

public int getId() {
return id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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._3707;

import java.math.BigInteger;

public class BigIntegerDto extends AbstractDto {
private final BigInteger value;

public static class Builder extends AbstractDto.Builder<Builder> {

private BigInteger value;

@Override
protected Builder self() {
return this;
}

public Builder value(BigInteger value) {
this.value = value;
return self();
}

@Override
public BigIntegerDto build() {
return new BigIntegerDto( this );
}
}

private BigIntegerDto(Builder builder) {
super( builder );
value = builder.value;
}

public BigInteger getValue() {
return value;
}

public static Builder builder() {
return new Builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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._3707;

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface Issue3707Mapper {

Issue3707Mapper INSTANCE = Mappers.getMapper( Issue3707Mapper.class );

StringDto clone(StringDto stringDto);

BigIntegerDto clone(BigIntegerDto bigIntegerDto);
}
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._3707;

import org.junit.jupiter.api.extension.RegisterExtension;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.GeneratedSource;

@WithClasses({
Issue3707Mapper.class,
AbstractDto.class,
BigIntegerDto.class,
StringDto.class,
})
@IssueKey("3707")
public class Issue3707Test {

@RegisterExtension
final GeneratedSource generatedSource = new GeneratedSource()
.addComparisonToFixtureFor( Issue3707Mapper.class );

@ProcessorTest
void shouldCompile() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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._3707;

public class StringDto extends AbstractDto {
private final String value;

public static class Builder extends AbstractDto.Builder<Builder> {

private String value;

@Override
protected Builder self() {
return this;
}

public Builder value(String value) {
this.value = value;
return self();
}

public Builder name(String value) {
return super.name( value );
}

public Builder id(Integer value) {
return super.id( value );
}

@Override
public StringDto build() {
return new StringDto( this );
}
}

private StringDto(Builder builder) {
super( builder );
value = builder.value;
}

public String getValue() {
return value;
}

public static Builder builder() {
return new Builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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._3707;

import javax.annotation.processing.Generated;

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2024-10-19T17:05:14+0300",
comments = "version: , compiler: javac, environment: Java 17.0.10 (Private Build)"
)
public class Issue3707MapperImpl implements Issue3707Mapper {

@Override
public StringDto clone(StringDto stringDto) {
if ( stringDto == null ) {
return null;
}

StringDto.Builder stringDto1 = StringDto.builder();

stringDto1.value( stringDto.getValue() );
stringDto1.name( stringDto.getName() );
stringDto1.id( stringDto.getId() );

return stringDto1.build();
}

@Override
public BigIntegerDto clone(BigIntegerDto bigIntegerDto) {
if ( bigIntegerDto == null ) {
return null;
}

BigIntegerDto.Builder bigIntegerDto1 = BigIntegerDto.builder();

bigIntegerDto1.name( bigIntegerDto.getName() );
bigIntegerDto1.id( bigIntegerDto.getId() );
bigIntegerDto1.value( bigIntegerDto.getValue() );

return bigIntegerDto1.build();
}
}