#2185 Fix StackOverflow error when recursive use of mapper in Mapper#uses

This commit is contained in:
Filip Hrisafov 2020-08-29 11:44:13 +02:00
parent c1feafef4c
commit a9451b1159
4 changed files with 108 additions and 5 deletions

View File

@ -176,11 +176,22 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
//Add all methods of used mappers in order to reference them in the aggregated model
if ( usedMapper.equals( mapperToImplement ) ) {
for ( DeclaredType mapper : mapperOptions.uses() ) {
methods.addAll( retrieveMethods(
asTypeElement( mapper ),
mapperToImplement,
mapperOptions,
prototypeMethods ) );
TypeElement usesMapperElement = asTypeElement( mapper );
if ( !mapperToImplement.equals( usesMapperElement ) ) {
methods.addAll( retrieveMethods(
usesMapperElement,
mapperToImplement,
mapperOptions,
prototypeMethods ) );
}
else {
messager.printMessage(
mapperToImplement,
mapperOptions.getAnnotationMirror(),
Message.RETRIEVAL_MAPPER_USES_CYCLE,
mapperToImplement
);
}
}
}

View File

@ -149,6 +149,7 @@ public enum Message {
RETRIEVAL_WILDCARD_SUPER_BOUND_SOURCE( "Can't generate mapping method for a wildcard super bound source." ),
RETRIEVAL_WILDCARD_EXTENDS_BOUND_RESULT( "Can't generate mapping method for a wildcard extends bound result." ),
RETRIEVAL_CONTEXT_PARAMS_WITH_SAME_TYPE( "The types of @Context parameters must be unique." ),
RETRIEVAL_MAPPER_USES_CYCLE( "The mapper %s is referenced itself in Mapper#uses.", Diagnostic.Kind.WARNING ),
INHERITINVERSECONFIGURATION_DUPLICATES( "Several matching inverse methods exist: %s(). Specify a name explicitly." ),
INHERITINVERSECONFIGURATION_INVALID_NAME( "None of the candidates %s() matches given name: \"%s\"." ),

View File

@ -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._2185;
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.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Filip Hrisafov
*/
@IssueKey("2185")
@RunWith(AnnotationProcessorTestRunner.class)
@WithClasses({
TodoMapper.class
})
public class Issue2185Test {
@Test
@ExpectedCompilationOutcome(value = CompilationResult.SUCCEEDED,
diagnostics = {
@Diagnostic(type = TodoMapper.class,
kind = javax.tools.Diagnostic.Kind.WARNING,
line = 14,
message = "The mapper org.mapstruct.ap.test.bugs._2185.TodoMapper is referenced itself in Mapper#uses.")
}
)
public void shouldCompile() {
TodoMapper.TodoResponse response = TodoMapper.INSTANCE.toResponse( new TodoMapper.TodoEntity( "test" ) );
assertThat( response ).isNotNull();
assertThat( response.getNote() ).isEqualTo( "test" );
}
}

View File

@ -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._2185;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper(uses = TodoMapper.class)
public interface TodoMapper {
TodoMapper INSTANCE = Mappers.getMapper( TodoMapper.class );
TodoResponse toResponse(TodoEntity entity);
class TodoResponse {
private final String note;
public TodoResponse(String note) {
this.note = note;
}
public String getNote() {
return note;
}
}
class TodoEntity {
private final String note;
public TodoEntity(String note) {
this.note = note;
}
public String getNote() {
return note;
}
}
}