#2773 Copy @Deprecated annotation from method or mapper to implementation

This commit is contained in:
Orange Add 2022-09-29 04:17:59 +08:00 committed by GitHub
parent 73e8fd6152
commit e979f506fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 314 additions and 2 deletions

View File

@ -31,6 +31,7 @@ public final class FullFeatureCompilationExclusionCliEnhancer implements Process
case JAVA_8:
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/injectionstrategy/jakarta_cdi/**/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/annotatewith/deprecated/jdk11/*.java" );
break;
case JAVA_9:
// TODO find out why this fails:

View File

@ -25,6 +25,7 @@
<additionalExclude2>x</additionalExclude2>
<additionalExclude3>x</additionalExclude3>
<additionalExclude4>x</additionalExclude4>
<additionalExclude5>x</additionalExclude5>
</properties>
<build>
@ -45,6 +46,7 @@
<exclude>${additionalExclude2}</exclude>
<exclude>${additionalExclude3}</exclude>
<exclude>${additionalExclude4}</exclude>
<exclude>${additionalExclude5}</exclude>
</excludes>
</configuration>
</plugin>

View File

@ -45,6 +45,7 @@ import org.mapstruct.tools.gem.GemDefinition;
*
* @author Gunnar Morling
*/
@GemDefinition(Deprecated.class)
@GemDefinition(AnnotateWith.class)
@GemDefinition(AnnotateWith.Element.class)
@GemDefinition(AnnotateWiths.class)

View File

@ -10,6 +10,7 @@ import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@ -31,6 +32,7 @@ import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.gem.AnnotateWithGem;
import org.mapstruct.ap.internal.gem.AnnotateWithsGem;
import org.mapstruct.ap.internal.gem.DeprecatedGem;
import org.mapstruct.ap.internal.gem.ElementGem;
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
@ -55,7 +57,6 @@ public class AdditionalAnnotationsBuilder
extends RepeatableAnnotations<AnnotateWithGem, AnnotateWithsGem, Annotation> {
private static final String ANNOTATE_WITH_FQN = "org.mapstruct.AnnotateWith";
private static final String ANNOTATE_WITHS_FQN = "org.mapstruct.AnnotateWiths";
private TypeFactory typeFactory;
private FormattingMessager messager;
@ -90,6 +91,45 @@ public class AdditionalAnnotationsBuilder
}
}
@Override
public Set<Annotation> getProcessedAnnotations(Element source) {
Set<Annotation> processedAnnotations = super.getProcessedAnnotations( source );
return addDeprecatedAnnotation( source, processedAnnotations );
}
private Set<Annotation> addDeprecatedAnnotation(Element source, Set<Annotation> annotations) {
DeprecatedGem deprecatedGem = DeprecatedGem.instanceOn( source );
if ( deprecatedGem == null ) {
return annotations;
}
Type deprecatedType = typeFactory.getType( Deprecated.class );
if ( annotations.stream().anyMatch( annotation -> annotation.getType().equals( deprecatedType ) ) ) {
messager.printMessage(
source,
deprecatedGem.mirror(),
Message.ANNOTATE_WITH_DUPLICATE,
deprecatedType.describe() );
return annotations;
}
List<AnnotationElement> annotationElements = new ArrayList<>();
if ( deprecatedGem.since() != null && deprecatedGem.since().hasValue() ) {
annotationElements.add( new AnnotationElement(
AnnotationElementType.STRING,
"since",
Collections.singletonList( deprecatedGem.since().getValue() )
) );
}
if ( deprecatedGem.forRemoval() != null && deprecatedGem.forRemoval().hasValue() ) {
annotationElements.add( new AnnotationElement(
AnnotationElementType.BOOLEAN,
"forRemoval",
Collections.singletonList( deprecatedGem.forRemoval().getValue() )
) );
}
annotations.add( new Annotation(deprecatedType, annotationElements ) );
return annotations;
}
private void addAndValidateMapping(Set<Annotation> mappings, Element source, AnnotateWithGem gem, Annotation anno) {
if ( anno.getType().getTypeElement().getAnnotation( Repeatable.class ) == null ) {
if ( mappings.stream().anyMatch( existing -> existing.getType().equals( anno.getType() ) ) ) {

View File

@ -593,5 +593,4 @@ public class AnnotateWithTest {
Method method = mapper.getClass().getMethod( "map", String.class );
assertThat( method.getAnnotation( CustomMethodOnlyAnnotation.class ) ).isNotNull();
}
}

View File

@ -0,0 +1,13 @@
/*
* 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.annotatewith.deprecated;
import org.mapstruct.Mapper;
@Mapper
@Deprecated
public class DeprecatedMapperWithClass {
}

View File

@ -0,0 +1,44 @@
/*
* 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.annotatewith.deprecated;
import org.mapstruct.AnnotateWith;
import org.mapstruct.Mapper;
import org.mapstruct.ap.test.annotatewith.CustomMethodOnlyAnnotation;
@Mapper
public interface DeprecatedMapperWithMethod {
@AnnotateWith(CustomMethodOnlyAnnotation.class)
@Deprecated
Target map(Source source);
class Source {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
class Target {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.annotatewith.deprecated;
import java.lang.reflect.Method;
import org.mapstruct.ap.test.annotatewith.CustomMethodOnlyAnnotation;
import org.mapstruct.ap.testutil.ProcessorTest;
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.factory.Mappers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author orange add
*/
public class DeprecatedTest {
@ProcessorTest
@WithClasses( { DeprecatedMapperWithMethod.class, CustomMethodOnlyAnnotation.class} )
public void deprecatedWithMethodCorrectCopy() throws NoSuchMethodException {
DeprecatedMapperWithMethod mapper = Mappers.getMapper( DeprecatedMapperWithMethod.class );
Method method = mapper.getClass().getMethod( "map", DeprecatedMapperWithMethod.Source.class );
Deprecated annotation = method.getAnnotation( Deprecated.class );
assertThat( annotation ).isNotNull();
}
@ProcessorTest
@WithClasses(DeprecatedMapperWithClass.class)
public void deprecatedWithClassCorrectCopy() {
DeprecatedMapperWithClass mapper = Mappers.getMapper( DeprecatedMapperWithClass.class );
Deprecated annotation = mapper.getClass().getAnnotation( Deprecated.class );
assertThat( annotation ).isNotNull();
}
@ProcessorTest
@WithClasses(RepeatDeprecatedMapper.class)
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED,
diagnostics = {
@Diagnostic(
kind = javax.tools.Diagnostic.Kind.WARNING,
type = RepeatDeprecatedMapper.class,
message = "Annotation \"Deprecated\" is already present with the " +
"same elements configuration."
)
}
)
public void deprecatedWithRepeat() {
}
}

View File

@ -0,0 +1,15 @@
/*
* 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.annotatewith.deprecated;
import org.mapstruct.AnnotateWith;
import org.mapstruct.Mapper;
@Mapper
@Deprecated
@AnnotateWith(Deprecated.class)
public class RepeatDeprecatedMapper {
}

View File

@ -0,0 +1,13 @@
/*
* 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.annotatewith.deprecated.jdk11;
import org.mapstruct.Mapper;
@Mapper
@Deprecated(since = "11")
public class DeprecatedMapperWithClass {
}

View File

@ -0,0 +1,44 @@
/*
* 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.annotatewith.deprecated.jdk11;
import org.mapstruct.AnnotateWith;
import org.mapstruct.Mapper;
import org.mapstruct.ap.test.annotatewith.CustomMethodOnlyAnnotation;
@Mapper
public interface DeprecatedMapperWithMethod {
@AnnotateWith(CustomMethodOnlyAnnotation.class)
@Deprecated(since = "18", forRemoval = false)
Target map(Source source);
class Source {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
class Target {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.annotatewith.deprecated.jdk11;
import java.lang.reflect.Method;
import org.mapstruct.ap.test.annotatewith.CustomMethodOnlyAnnotation;
import org.mapstruct.ap.testutil.ProcessorTest;
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.factory.Mappers;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author orange add
*/
public class DeprecatedTest {
@ProcessorTest
@WithClasses({ DeprecatedMapperWithMethod.class, CustomMethodOnlyAnnotation.class})
public void deprecatedWithMethodCorrectCopyForJdk11() throws NoSuchMethodException {
DeprecatedMapperWithMethod mapper = Mappers.getMapper( DeprecatedMapperWithMethod.class );
Method method = mapper.getClass().getMethod( "map", DeprecatedMapperWithMethod.Source.class );
Deprecated annotation = method.getAnnotation( Deprecated.class );
assertThat( annotation ).isNotNull();
assertThat( annotation.since() ).isEqualTo( "18" );
assertThat( annotation.forRemoval() ).isEqualTo( false );
}
@ProcessorTest
@WithClasses(DeprecatedMapperWithClass.class)
public void deprecatedWithClassCorrectCopyForJdk11() {
DeprecatedMapperWithClass mapper = Mappers.getMapper( DeprecatedMapperWithClass.class );
Deprecated annotation = mapper.getClass().getAnnotation( Deprecated.class );
assertThat( annotation ).isNotNull();
assertThat( annotation.since() ).isEqualTo( "11" );
}
@ProcessorTest
@WithClasses( { RepeatDeprecatedMapperWithParams.class})
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED,
diagnostics = {
@Diagnostic(
kind = javax.tools.Diagnostic.Kind.WARNING,
type = RepeatDeprecatedMapperWithParams.class,
message = "Annotation \"Deprecated\" is already present with the " +
"same elements configuration."
)
}
)
public void bothExistPriorityAnnotateWithForJdk11() {
RepeatDeprecatedMapperWithParams mapper = Mappers.getMapper( RepeatDeprecatedMapperWithParams.class );
Deprecated deprecated = mapper.getClass().getAnnotation( Deprecated.class );
assertThat( deprecated ).isNotNull();
assertThat( deprecated.since() ).isEqualTo( "1.5" );
assertThat( deprecated.forRemoval() ).isEqualTo( false );
}
}

View File

@ -0,0 +1,21 @@
/*
* 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.annotatewith.deprecated.jdk11;
import org.mapstruct.AnnotateWith;
import org.mapstruct.Mapper;
@Mapper
@Deprecated( since = "1.8" )
@AnnotateWith(
value = Deprecated.class,
elements = {
@AnnotateWith.Element( name = "forRemoval", booleans = false),
@AnnotateWith.Element( name = "since", strings = "1.5")
}
)
public class RepeatDeprecatedMapperWithParams {
}