mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1904 Create compilation error if a mapper could not be created due to a TypeHierarchyErroneousException
This commit is contained in:
parent
750ce48023
commit
e92e3b45c6
@ -27,6 +27,7 @@ import javax.lang.model.SourceVersion;
|
|||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.lang.model.element.Name;
|
import javax.lang.model.element.Name;
|
||||||
|
import javax.lang.model.element.QualifiedNameable;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.util.ElementKindVisitor6;
|
import javax.lang.model.util.ElementKindVisitor6;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
@ -115,7 +116,7 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
* generated by other processors), this mapper will not be generated; That's fine, the compiler will raise an error
|
* generated by other processors), this mapper will not be generated; That's fine, the compiler will raise an error
|
||||||
* due to the inconsistent Java types used as source or target anyways.
|
* due to the inconsistent Java types used as source or target anyways.
|
||||||
*/
|
*/
|
||||||
private Set<TypeElement> deferredMappers = new HashSet<>();
|
private Set<DeferredMapper> deferredMappers = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||||
@ -163,6 +164,40 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
Set<TypeElement> mappers = getMappers( annotations, roundEnvironment );
|
Set<TypeElement> mappers = getMappers( annotations, roundEnvironment );
|
||||||
processMapperElements( mappers, roundContext );
|
processMapperElements( mappers, roundContext );
|
||||||
}
|
}
|
||||||
|
else if ( !deferredMappers.isEmpty() ) {
|
||||||
|
// If the processing is over and there are deferred mappers it means something wrong occurred and
|
||||||
|
// MapStruct didn't generate implementations for those
|
||||||
|
for ( DeferredMapper deferredMapper : deferredMappers ) {
|
||||||
|
|
||||||
|
TypeElement deferredMapperElement = deferredMapper.deferredMapperElement;
|
||||||
|
Element erroneousElement = deferredMapper.erroneousElement;
|
||||||
|
String erroneousElementName;
|
||||||
|
|
||||||
|
if ( erroneousElement instanceof QualifiedNameable ) {
|
||||||
|
erroneousElementName = ( (QualifiedNameable) erroneousElement ).getQualifiedName().toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
erroneousElementName = erroneousElement.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// When running on Java 8 we need to fetch the deferredMapperElement again.
|
||||||
|
// Otherwise the reporting will not work properly
|
||||||
|
deferredMapperElement = annotationProcessorContext.getElementUtils()
|
||||||
|
.getTypeElement( deferredMapperElement.getQualifiedName() );
|
||||||
|
|
||||||
|
processingEnv.getMessager()
|
||||||
|
.printMessage(
|
||||||
|
Kind.ERROR,
|
||||||
|
"No implementation was created for " + deferredMapperElement.getSimpleName() +
|
||||||
|
" due to having a problem in the erroneous element " + erroneousElementName + "." +
|
||||||
|
" Hint: this often means that some other annotation processor was supposed to" +
|
||||||
|
" process the erroneous element. You can also enable MapStruct verbose mode by setting" +
|
||||||
|
" -Amapstruct.verbose=true as a compilation argument.",
|
||||||
|
deferredMapperElement
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return ANNOTATIONS_CLAIMED_EXCLUSIVELY;
|
return ANNOTATIONS_CLAIMED_EXCLUSIVELY;
|
||||||
}
|
}
|
||||||
@ -174,7 +209,8 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
private Set<TypeElement> getAndResetDeferredMappers() {
|
private Set<TypeElement> getAndResetDeferredMappers() {
|
||||||
Set<TypeElement> deferred = new HashSet<>( deferredMappers.size() );
|
Set<TypeElement> deferred = new HashSet<>( deferredMappers.size() );
|
||||||
|
|
||||||
for (TypeElement element : deferredMappers ) {
|
for ( DeferredMapper deferredMapper : deferredMappers ) {
|
||||||
|
TypeElement element = deferredMapper.deferredMapperElement;
|
||||||
deferred.add( processingEnv.getElementUtils().getTypeElement( element.getQualifiedName() ) );
|
deferred.add( processingEnv.getElementUtils().getTypeElement( element.getQualifiedName() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,12 +265,15 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
processMapperTypeElement( context, mapperElement );
|
processMapperTypeElement( context, mapperElement );
|
||||||
}
|
}
|
||||||
catch ( TypeHierarchyErroneousException thie ) {
|
catch ( TypeHierarchyErroneousException thie ) {
|
||||||
|
Element erroneousElement = roundContext.getAnnotationProcessorContext()
|
||||||
|
.getTypeUtils()
|
||||||
|
.asElement( thie.getType() );
|
||||||
if ( options.isVerbose() ) {
|
if ( options.isVerbose() ) {
|
||||||
processingEnv.getMessager().printMessage(
|
processingEnv.getMessager().printMessage(
|
||||||
Kind.NOTE, "MapStruct: referred types not available (yet), deferring mapper: "
|
Kind.NOTE, "MapStruct: referred types not available (yet), deferring mapper: "
|
||||||
+ mapperElement );
|
+ mapperElement );
|
||||||
}
|
}
|
||||||
deferredMappers.add( mapperElement );
|
deferredMappers.add( new DeferredMapper( mapperElement, erroneousElement ) );
|
||||||
}
|
}
|
||||||
catch ( Throwable t ) {
|
catch ( Throwable t ) {
|
||||||
handleUncaughtError( mapperElement, t );
|
handleUncaughtError( mapperElement, t );
|
||||||
@ -347,4 +386,15 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
return Integer.compare( o1.getPriority(), o2.getPriority() );
|
return Integer.compare( o1.getPriority(), o2.getPriority() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DeferredMapper {
|
||||||
|
|
||||||
|
private final TypeElement deferredMapperElement;
|
||||||
|
private final Element erroneousElement;
|
||||||
|
|
||||||
|
private DeferredMapper(TypeElement deferredMapperElement, Element erroneousElement) {
|
||||||
|
this.deferredMapperElement = deferredMapperElement;
|
||||||
|
this.erroneousElement = erroneousElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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._1904;
|
||||||
|
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class AstModifyingAnnotationProcessorSaysNo implements AstModifyingAnnotationProcessor {
|
||||||
|
@Override
|
||||||
|
public boolean isTypeComplete(TypeMirror type) {
|
||||||
|
if ( type.toString().contains( "CarManualDto" ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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._1904;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface Issue1904Mapper {
|
||||||
|
|
||||||
|
CarManualDto translateManual(CarManual manual);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
class CarManual {
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
class CarManualDto {
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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._1904;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@IssueKey("1904")
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
@WithClasses({
|
||||||
|
Issue1904Mapper.class,
|
||||||
|
})
|
||||||
|
@WithServiceImplementation(
|
||||||
|
provides = AstModifyingAnnotationProcessor.class,
|
||||||
|
value = AstModifyingAnnotationProcessorSaysNo.class
|
||||||
|
)
|
||||||
|
public class Issue1904Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ExpectedCompilationOutcome(value = CompilationResult.FAILED, diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
type = Issue1904Mapper.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 14,
|
||||||
|
messageRegExp = ".*No implementation was created for Issue1904Mapper due to having a problem in the " +
|
||||||
|
"erroneous element .*\\.CarManualDto. Hint: this often means that some other annotation processor " +
|
||||||
|
"was supposed to process the erroneous element. You can also enable MapStruct verbose mode by " +
|
||||||
|
"setting -Amapstruct.verbose=true as a compilation argument."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
public void shouldHaveCompilationErrorIfMapperCouldNotBeCreated() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,9 @@ import org.mapstruct.ap.spi.ImmutablesBuilderProvider;
|
|||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||||
|
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.compilation.annotation.ExpectedNote;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
@ -57,6 +60,15 @@ public class VerboseTest {
|
|||||||
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
@ProcessorOption(name = "mapstruct.verbose", value = "true")
|
||||||
@WithClasses(CreateBeanMapping.class)
|
@WithClasses(CreateBeanMapping.class)
|
||||||
@ExpectedNote("^MapStruct: referred types not available \\(yet\\), deferring mapper:.*CreateBeanMapping.*$")
|
@ExpectedNote("^MapStruct: referred types not available \\(yet\\), deferring mapper:.*CreateBeanMapping.*$")
|
||||||
|
@ExpectedCompilationOutcome(value = CompilationResult.FAILED, diagnostics = {
|
||||||
|
@Diagnostic(
|
||||||
|
type = CreateBeanMapping.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 12,
|
||||||
|
messageRegExp = ".*No implementation was created for CreateBeanMapping due to having a problem in the " +
|
||||||
|
"erroneous element .*"
|
||||||
|
)
|
||||||
|
})
|
||||||
public void testDeferred() {
|
public void testDeferred() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user