mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1574: Support for annotating the generated code with custom annotations
Add new `@AnnotateWith` annotation. This annotation can be used to instruct the MapStruct processor to generate custom annotations in the generated code.
This commit is contained in:
parent
8fa286fe4c
commit
849085e026
176
core/src/main/java/org/mapstruct/AnnotateWith.java
Normal file
176
core/src/main/java/org/mapstruct/AnnotateWith.java
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
|
||||
/**
|
||||
* This can be used to have mapstruct generate additional annotations on classes/methods.
|
||||
* <p>
|
||||
* Examples based on the spring framework annotations.
|
||||
* </p>
|
||||
* Marking a class as `Lazy`:
|
||||
*
|
||||
* <pre><code>
|
||||
* @AnnotateWith( value = Lazy.class )
|
||||
* @Mapper
|
||||
* public interface FooMapper {
|
||||
* // mapper code
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* The following code would be generated:
|
||||
*
|
||||
* <pre><code>
|
||||
* @Lazy
|
||||
* public class FooMapperImpl implements FooMapper {
|
||||
* // mapper code
|
||||
* }
|
||||
* </code></pre>
|
||||
* Setting the profile on the generated implementation:
|
||||
*
|
||||
* <pre><code>
|
||||
* @AnnotateWith( value = Profile.class, elements = @AnnotateWith.Element( strings = "prod" ) )
|
||||
* @Mapper
|
||||
* public interface FooMapper {
|
||||
* // mapper code
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* The following code would be generated:
|
||||
*
|
||||
* <pre><code>
|
||||
* @Profile( value = "prod" )
|
||||
* public class FooMapperImpl implements FooMapper {
|
||||
* // mapper code
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* @author Ben Zegveld
|
||||
* @since 1.6
|
||||
*/
|
||||
@Repeatable( AnnotateWiths.class )
|
||||
@Retention( CLASS )
|
||||
@Target( { TYPE, METHOD, ANNOTATION_TYPE } )
|
||||
public @interface AnnotateWith {
|
||||
/**
|
||||
* @return the annotation class that needs to be added.
|
||||
*/
|
||||
Class<? extends Annotation> value();
|
||||
|
||||
/**
|
||||
* @return the annotation elements that are to be applied to this annotation.
|
||||
*/
|
||||
Element[] elements() default {};
|
||||
|
||||
/**
|
||||
* Used in combination with {@link AnnotateWith} to configure the annotation elements. Only 1 value type may be used
|
||||
* within the same annotation at a time. For example mixing shorts and ints is not allowed.
|
||||
*
|
||||
* @author Ben Zegveld
|
||||
* @since 1.6
|
||||
*/
|
||||
@interface Element {
|
||||
/**
|
||||
* @return name of the annotation element.
|
||||
*/
|
||||
String name() default "value";
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return short value(s) for the annotation element.
|
||||
*/
|
||||
short[] shorts() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return byte value(s) for the annotation element.
|
||||
*/
|
||||
byte[] bytes() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return int value(s) for the annotation element.
|
||||
*/
|
||||
int[] ints() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return long value(s) for the annotation element.
|
||||
*/
|
||||
long[] longs() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return float value(s) for the annotation element.
|
||||
*/
|
||||
float[] floats() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return double value(s) for the annotation element.
|
||||
*/
|
||||
double[] doubles() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return char value(s) for the annotation element.
|
||||
*/
|
||||
char[] chars() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return boolean value(s) for the annotation element.
|
||||
*/
|
||||
boolean[] booleans() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return string value(s) for the annotation element.
|
||||
*/
|
||||
String[] strings() default {};
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields.
|
||||
*
|
||||
* @return class value(s) for the annotation element.
|
||||
*/
|
||||
Class<?>[] classes() default {};
|
||||
|
||||
/**
|
||||
* only used in conjunction with the {@link #enums()} annotation element.
|
||||
*
|
||||
* @return the class of the enum.
|
||||
*/
|
||||
Class<? extends Enum<?>> enumClass() default NullEnum.class;
|
||||
|
||||
/**
|
||||
* cannot be used in conjunction with other value fields. {@link #enumClass()} is also required when using
|
||||
* {@link #enums()}
|
||||
*
|
||||
* @return enum value(s) for the annotation element.
|
||||
*/
|
||||
String[] enums() default {};
|
||||
|
||||
}
|
||||
}
|
31
core/src/main/java/org/mapstruct/AnnotateWiths.java
Normal file
31
core/src/main/java/org/mapstruct/AnnotateWiths.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
|
||||
/**
|
||||
* This can be used to have mapstruct generate additional annotations on classes/methods.
|
||||
*
|
||||
* @author Ben Zegveld
|
||||
* @since 1.6
|
||||
*/
|
||||
@Retention( CLASS )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface AnnotateWiths {
|
||||
|
||||
/**
|
||||
* The configuration of the additional annotations.
|
||||
*
|
||||
* @return The configuration of the additional annotations.
|
||||
*/
|
||||
AnnotateWith[] value();
|
||||
}
|
15
core/src/main/java/org/mapstruct/NullEnum.java
Normal file
15
core/src/main/java/org/mapstruct/NullEnum.java
Normal 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;
|
||||
|
||||
/**
|
||||
* To be used as a default value for enum class annotation elements.
|
||||
*
|
||||
* @author Ben Zegveld
|
||||
* @since 1.6
|
||||
*/
|
||||
enum NullEnum {
|
||||
}
|
@ -721,3 +721,43 @@ i.e. You can map from `Map<String, Integer>` where for each property a conversio
|
||||
When a raw map or a map that does not have a String as a key is used, then a warning will be generated.
|
||||
The warning is not generated if the map itself is mapped into some other target property directly as is.
|
||||
====
|
||||
|
||||
[[adding-annotations]]
|
||||
=== Adding annotations
|
||||
|
||||
Other frameworks sometimes requires you to add annotations to certain classes so that they can easily detect the mappers.
|
||||
Using the `@AnnotateWith` annotation you can generate an annotation at the specified location.
|
||||
|
||||
For example Apache Camel has a `@Converter` annotation which you can apply to generated mappers using the `@AnnotateWith` annotation.
|
||||
|
||||
.AnnotateWith source example
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mapper
|
||||
@AnnotateWith(
|
||||
value = Converter.class,
|
||||
elements = @AnnotateWith.Element( name = "generateBulkLoader", booleans = true )
|
||||
)
|
||||
public interface MyConverter {
|
||||
@AnnotateWith( Converter.class )
|
||||
DomainObject map( DtoObject dto );
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
.AnnotateWith generated mapper
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Converter( generateBulkLoader = true )
|
||||
public class MyConverterImpl implements MyConverter {
|
||||
@Converter
|
||||
public DomainObject map( DtoObject dto ) {
|
||||
// default mapping behaviour
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
@ -9,6 +9,8 @@ import javax.xml.bind.annotation.XmlElementDecl;
|
||||
import javax.xml.bind.annotation.XmlElementRef;
|
||||
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWiths;
|
||||
import org.mapstruct.BeanMapping;
|
||||
import org.mapstruct.BeforeMapping;
|
||||
import org.mapstruct.Builder;
|
||||
@ -43,6 +45,9 @@ import org.mapstruct.tools.gem.GemDefinition;
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
@GemDefinition(AnnotateWith.class)
|
||||
@GemDefinition(AnnotateWith.Element.class)
|
||||
@GemDefinition(AnnotateWiths.class)
|
||||
@GemDefinition(Mapper.class)
|
||||
@GemDefinition(Mapping.class)
|
||||
@GemDefinition(Mappings.class)
|
||||
|
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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.internal.model;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
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.ElementGem;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||
import org.mapstruct.ap.internal.model.annotation.EnumAnnotationElementHolder;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.internal.util.ElementUtils;
|
||||
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||
import org.mapstruct.ap.internal.util.Message;
|
||||
import org.mapstruct.ap.internal.util.RepeatableAnnotations;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||
import org.mapstruct.tools.gem.GemValue;
|
||||
|
||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
* @since 1.5
|
||||
*/
|
||||
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;
|
||||
|
||||
public AdditionalAnnotationsBuilder(ElementUtils elementUtils, TypeFactory typeFactory,
|
||||
FormattingMessager messager) {
|
||||
super( elementUtils, ANNOTATE_WITH_FQN, ANNOTATE_WITHS_FQN );
|
||||
this.typeFactory = typeFactory;
|
||||
this.messager = messager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotateWithGem singularInstanceOn(Element element) {
|
||||
return AnnotateWithGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotateWithsGem multipleInstanceOn(Element element) {
|
||||
return AnnotateWithsGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addInstance(AnnotateWithGem gem, Element source, Set<Annotation> mappings) {
|
||||
buildAnnotation( gem, source ).ifPresent( t -> addAndValidateMapping( mappings, source, gem, t ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addInstances(AnnotateWithsGem gem, Element source, Set<Annotation> mappings) {
|
||||
for ( AnnotateWithGem annotateWithGem : gem.value().get() ) {
|
||||
buildAnnotation(
|
||||
annotateWithGem,
|
||||
source ).ifPresent( t -> addAndValidateMapping( mappings, source, annotateWithGem, t ) );
|
||||
}
|
||||
}
|
||||
|
||||
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() ) ) ) {
|
||||
messager.printMessage(
|
||||
source,
|
||||
gem.mirror(),
|
||||
Message.ANNOTATE_WITH_ANNOTATION_IS_NOT_REPEATABLE,
|
||||
anno.getType().describe() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( mappings.stream().anyMatch( existing -> {
|
||||
return existing.getType().equals( anno.getType() )
|
||||
&& existing.getProperties().equals( anno.getProperties() );
|
||||
} ) ) {
|
||||
messager.printMessage(
|
||||
source,
|
||||
gem.mirror(),
|
||||
Message.ANNOTATE_WITH_DUPLICATE,
|
||||
anno.getType().describe() );
|
||||
return;
|
||||
}
|
||||
mappings.add( anno );
|
||||
}
|
||||
|
||||
private Optional<Annotation> buildAnnotation(AnnotateWithGem annotationGem, Element element) {
|
||||
Type annotationType = typeFactory.getType( getTypeMirror( annotationGem.value() ) );
|
||||
List<ElementGem> eleGems = annotationGem.elements().get();
|
||||
if ( isValid( annotationType, eleGems, element, annotationGem.mirror() ) ) {
|
||||
return Optional.of( new Annotation( annotationType, convertToProperties( eleGems ) ) );
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private List<AnnotationElement> convertToProperties(List<ElementGem> eleGems) {
|
||||
return eleGems.stream().map( gem -> convertToProperty( gem, typeFactory ) ).collect( Collectors.toList() );
|
||||
}
|
||||
|
||||
private enum ConvertToProperty {
|
||||
BOOLEAN(
|
||||
AnnotationElementType.BOOLEAN,
|
||||
(eleGem, typeFactory) -> eleGem.booleans().get(),
|
||||
eleGem -> eleGem.booleans().hasValue()
|
||||
),
|
||||
BYTE(
|
||||
AnnotationElementType.BYTE,
|
||||
(eleGem, typeFactory) -> eleGem.bytes().get(),
|
||||
eleGem -> eleGem.bytes().hasValue()
|
||||
),
|
||||
CHARACTER(
|
||||
AnnotationElementType.CHARACTER,
|
||||
(eleGem, typeFactory) -> eleGem.chars().get(),
|
||||
eleGem -> eleGem.chars().hasValue()
|
||||
),
|
||||
CLASSES(
|
||||
AnnotationElementType.CLASS,
|
||||
(eleGem, typeFactory) -> {
|
||||
return eleGem.classes().get().stream().map( typeFactory::getType ).collect( Collectors.toList() );
|
||||
},
|
||||
eleGem -> eleGem.classes().hasValue()
|
||||
),
|
||||
DOUBLE(
|
||||
AnnotationElementType.DOUBLE,
|
||||
(eleGem, typeFactory) -> eleGem.doubles().get(),
|
||||
eleGem -> eleGem.doubles().hasValue()
|
||||
),
|
||||
ENUM(
|
||||
AnnotationElementType.ENUM,
|
||||
(eleGem, typeFactory) -> {
|
||||
List<EnumAnnotationElementHolder> values = new ArrayList<>();
|
||||
for ( String enumName : eleGem.enums().get() ) {
|
||||
Type type = typeFactory.getType( eleGem.enumClass().get() );
|
||||
values.add( new EnumAnnotationElementHolder( type, enumName ) );
|
||||
}
|
||||
return values;
|
||||
},
|
||||
eleGem -> eleGem.enums().hasValue() && eleGem.enumClass().hasValue()
|
||||
),
|
||||
FLOAT(
|
||||
AnnotationElementType.FLOAT,
|
||||
(eleGem, typeFactory) -> eleGem.floats().get(),
|
||||
eleGem -> eleGem.floats().hasValue()
|
||||
),
|
||||
INT(
|
||||
AnnotationElementType.INTEGER,
|
||||
(eleGem, typeFactory) -> eleGem.ints().get(),
|
||||
eleGem -> eleGem.ints().hasValue()
|
||||
),
|
||||
LONG(
|
||||
AnnotationElementType.LONG,
|
||||
(eleGem, typeFactory) -> eleGem.longs().get(),
|
||||
eleGem -> eleGem.longs().hasValue()
|
||||
),
|
||||
SHORT(
|
||||
AnnotationElementType.SHORT,
|
||||
(eleGem, typeFactory) -> eleGem.shorts().get(),
|
||||
eleGem -> eleGem.shorts().hasValue()
|
||||
),
|
||||
STRING(
|
||||
AnnotationElementType.STRING,
|
||||
(eleGem, typeFactory) -> eleGem.strings().get(),
|
||||
eleGem -> eleGem.strings().hasValue()
|
||||
);
|
||||
|
||||
private final AnnotationElementType type;
|
||||
private final BiFunction<ElementGem, TypeFactory, List<? extends Object>> factory;
|
||||
private final Predicate<ElementGem> usabilityChecker;
|
||||
|
||||
ConvertToProperty(AnnotationElementType type,
|
||||
BiFunction<ElementGem, TypeFactory, List<? extends Object>> factory,
|
||||
Predicate<ElementGem> usabilityChecker) {
|
||||
this.type = type;
|
||||
this.factory = factory;
|
||||
this.usabilityChecker = usabilityChecker;
|
||||
}
|
||||
|
||||
AnnotationElement toProperty(ElementGem eleGem, TypeFactory typeFactory) {
|
||||
return new AnnotationElement(
|
||||
type,
|
||||
eleGem.name().get(),
|
||||
factory.apply( eleGem, typeFactory )
|
||||
);
|
||||
}
|
||||
|
||||
boolean isUsable(ElementGem eleGem) {
|
||||
return usabilityChecker.test( eleGem );
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationElement convertToProperty(ElementGem eleGem, TypeFactory typeFactory) {
|
||||
for ( ConvertToProperty convertToJava : ConvertToProperty.values() ) {
|
||||
if ( convertToJava.isUsable( eleGem ) ) {
|
||||
return convertToJava.toProperty( eleGem, typeFactory );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isValid(Type annotationType, List<ElementGem> eleGems, Element element,
|
||||
AnnotationMirror annotationMirror) {
|
||||
boolean isValid = true;
|
||||
if ( !annotationIsAllowed( annotationType, element, annotationMirror ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
List<ExecutableElement> annotationElements = methodsIn( annotationType.getTypeElement()
|
||||
.getEnclosedElements() );
|
||||
if ( !allRequiredElementsArePresent( annotationType, annotationElements, eleGems, element,
|
||||
annotationMirror ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
if ( !allElementsAreKnownInAnnotation( annotationType, annotationElements, eleGems, element ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
if ( !allElementsAreOfCorrectType( annotationType, annotationElements, eleGems, element ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
if ( !enumConstructionIsCorrectlyUsed( eleGems, element ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
if ( !allElementsAreUnique( eleGems, element ) ) {
|
||||
isValid = false;
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean allElementsAreUnique(List<ElementGem> eleGems, Element element) {
|
||||
boolean isValid = true;
|
||||
List<String> checkedElements = new ArrayList<>();
|
||||
for ( ElementGem elementGem : eleGems ) {
|
||||
String elementName = elementGem.name().get();
|
||||
if ( checkedElements.contains( elementName ) ) {
|
||||
isValid = false;
|
||||
messager
|
||||
.printMessage(
|
||||
element,
|
||||
elementGem.mirror(),
|
||||
Message.ANNOTATE_WITH_DUPLICATE_PARAMETER,
|
||||
elementName );
|
||||
}
|
||||
else {
|
||||
checkedElements.add( elementName );
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean enumConstructionIsCorrectlyUsed(List<ElementGem> eleGems, Element element) {
|
||||
boolean isValid = true;
|
||||
for ( ElementGem elementGem : eleGems ) {
|
||||
if ( elementGem.enums().hasValue() ) {
|
||||
if ( elementGem.enumClass().getValue() == null ) {
|
||||
isValid = false;
|
||||
messager
|
||||
.printMessage(
|
||||
element,
|
||||
elementGem.mirror(),
|
||||
Message.ANNOTATE_WITH_ENUM_CLASS_NOT_DEFINED );
|
||||
}
|
||||
else {
|
||||
Type type = typeFactory.getType( getTypeMirror( elementGem.enumClass() ) );
|
||||
if ( type.isEnumType() ) {
|
||||
List<String> enumConstants = type.getEnumConstants();
|
||||
for ( String enumName : elementGem.enums().get() ) {
|
||||
if ( !enumConstants.contains( enumName ) ) {
|
||||
isValid = false;
|
||||
messager
|
||||
.printMessage(
|
||||
element,
|
||||
elementGem.mirror(),
|
||||
elementGem.enums().getAnnotationValue(),
|
||||
Message.ANNOTATE_WITH_ENUM_VALUE_DOES_NOT_EXIST,
|
||||
type.describe(),
|
||||
enumName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( elementGem.enumClass().getValue() != null ) {
|
||||
isValid = false;
|
||||
messager.printMessage( element, elementGem.mirror(), Message.ANNOTATE_WITH_ENUMS_NOT_DEFINED );
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean annotationIsAllowed(Type annotationType, Element element, AnnotationMirror annotationMirror) {
|
||||
Target target = annotationType.getTypeElement().getAnnotation( Target.class );
|
||||
if ( target == null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<ElementType> annotationTargets = Stream.of( target.value() )
|
||||
// The eclipse compiler returns null for some values
|
||||
// Therefore, we filter out null values
|
||||
.filter( Objects::nonNull )
|
||||
.collect( Collectors.toCollection( () -> EnumSet.noneOf( ElementType.class ) ) );
|
||||
|
||||
boolean isValid = true;
|
||||
if ( isTypeTarget( element ) && !annotationTargets.contains( ElementType.TYPE ) ) {
|
||||
isValid = false;
|
||||
messager.printMessage(
|
||||
element,
|
||||
annotationMirror,
|
||||
Message.ANNOTATE_WITH_NOT_ALLOWED_ON_CLASS,
|
||||
annotationType.describe()
|
||||
);
|
||||
}
|
||||
if ( isMethodTarget( element ) && !annotationTargets.contains( ElementType.METHOD ) ) {
|
||||
isValid = false;
|
||||
messager.printMessage(
|
||||
element,
|
||||
annotationMirror,
|
||||
Message.ANNOTATE_WITH_NOT_ALLOWED_ON_METHODS,
|
||||
annotationType.describe()
|
||||
);
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean isTypeTarget(Element element) {
|
||||
return element.getKind().isInterface() || element.getKind().isClass();
|
||||
}
|
||||
|
||||
private boolean isMethodTarget(Element element) {
|
||||
return element.getKind() == ElementKind.METHOD;
|
||||
}
|
||||
|
||||
private boolean allElementsAreKnownInAnnotation(Type annotationType, List<ExecutableElement> annotationParameters,
|
||||
List<ElementGem> eleGems, Element element) {
|
||||
Set<String> allowedAnnotationParameters = annotationParameters.stream()
|
||||
.map( ee -> ee.getSimpleName().toString() )
|
||||
.collect( Collectors.toSet() );
|
||||
boolean isValid = true;
|
||||
for ( ElementGem eleGem : eleGems ) {
|
||||
if ( eleGem.name().isValid()
|
||||
&& !allowedAnnotationParameters.contains( eleGem.name().get() ) ) {
|
||||
isValid = false;
|
||||
messager
|
||||
.printMessage(
|
||||
element,
|
||||
eleGem.mirror(),
|
||||
eleGem.name().getAnnotationValue(),
|
||||
Message.ANNOTATE_WITH_UNKNOWN_PARAMETER,
|
||||
eleGem.name().get(),
|
||||
annotationType.describe(),
|
||||
Strings.getMostSimilarWord( eleGem.name().get(), allowedAnnotationParameters )
|
||||
);
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean allRequiredElementsArePresent(Type annotationType, List<ExecutableElement> annotationParameters,
|
||||
List<ElementGem> elements, Element element,
|
||||
AnnotationMirror annotationMirror) {
|
||||
|
||||
boolean valid = true;
|
||||
for ( ExecutableElement annotationParameter : annotationParameters ) {
|
||||
if ( annotationParameter.getDefaultValue() == null ) {
|
||||
// Mandatory parameter, must be present in the elements
|
||||
String parameterName = annotationParameter.getSimpleName().toString();
|
||||
boolean elementGemDefined = false;
|
||||
for ( ElementGem elementGem : elements ) {
|
||||
if ( elementGem.isValid() && elementGem.name().get().equals( parameterName ) ) {
|
||||
elementGemDefined = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !elementGemDefined ) {
|
||||
valid = false;
|
||||
messager
|
||||
.printMessage(
|
||||
element,
|
||||
annotationMirror,
|
||||
Message.ANNOTATE_WITH_MISSING_REQUIRED_PARAMETER,
|
||||
parameterName,
|
||||
annotationType.describe()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private boolean allElementsAreOfCorrectType(Type annotationType, List<ExecutableElement> annotationParameters,
|
||||
List<ElementGem> elements,
|
||||
Element element) {
|
||||
Map<String, ExecutableElement> annotationParametersByName =
|
||||
annotationParameters.stream()
|
||||
.collect( Collectors.toMap( ee -> ee.getSimpleName().toString(), Function.identity() ) );
|
||||
boolean isValid = true;
|
||||
for ( ElementGem eleGem : elements ) {
|
||||
Type annotationParameterType = getAnnotationParameterType( annotationParametersByName, eleGem );
|
||||
Type annotationParameterTypeSingular = getNonArrayType( annotationParameterType );
|
||||
if ( annotationParameterTypeSingular == null ) {
|
||||
continue;
|
||||
}
|
||||
if ( hasTooManyDifferentTypes( eleGem ) ) {
|
||||
isValid = false;
|
||||
messager.printMessage(
|
||||
element,
|
||||
eleGem.mirror(),
|
||||
eleGem.name().getAnnotationValue(),
|
||||
Message.ANNOTATE_WITH_TOO_MANY_VALUE_TYPES,
|
||||
eleGem.name().get(),
|
||||
annotationParameterType.describe(),
|
||||
annotationType.describe()
|
||||
);
|
||||
}
|
||||
else {
|
||||
Map<Type, Integer> elementTypes = getParameterTypes( eleGem );
|
||||
Set<ElementGem> reportedSizeError = new HashSet<>();
|
||||
for ( Type eleGemType : elementTypes.keySet() ) {
|
||||
if ( !sameTypeOrAssignableClass( annotationParameterTypeSingular, eleGemType ) ) {
|
||||
isValid = false;
|
||||
messager.printMessage(
|
||||
element,
|
||||
eleGem.mirror(),
|
||||
eleGem.name().getAnnotationValue(),
|
||||
Message.ANNOTATE_WITH_WRONG_PARAMETER,
|
||||
eleGem.name().get(),
|
||||
eleGemType.describe(),
|
||||
annotationParameterType.describe(),
|
||||
annotationType.describe()
|
||||
);
|
||||
}
|
||||
else if ( !annotationParameterType.isArrayType()
|
||||
&& elementTypes.get( eleGemType ) > 1
|
||||
&& !reportedSizeError.contains( eleGem ) ) {
|
||||
isValid = false;
|
||||
messager.printMessage(
|
||||
element,
|
||||
eleGem.mirror(),
|
||||
Message.ANNOTATE_WITH_PARAMETER_ARRAY_NOT_EXPECTED,
|
||||
eleGem.name().get(),
|
||||
annotationType.describe()
|
||||
);
|
||||
reportedSizeError.add( eleGem );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private boolean hasTooManyDifferentTypes( ElementGem eleGem ) {
|
||||
return Arrays.stream( ConvertToProperty.values() )
|
||||
.filter( anotationElement -> anotationElement.isUsable( eleGem ) )
|
||||
.count() > 1;
|
||||
}
|
||||
|
||||
private Type getNonArrayType(Type annotationParameterType) {
|
||||
if ( annotationParameterType == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( annotationParameterType.isArrayType() ) {
|
||||
return annotationParameterType.getComponentType();
|
||||
}
|
||||
|
||||
return annotationParameterType;
|
||||
}
|
||||
|
||||
private boolean sameTypeOrAssignableClass(Type annotationParameterType, Type eleGemType) {
|
||||
return annotationParameterType.equals( eleGemType )
|
||||
|| eleGemType.isAssignableTo( getTypeBound( annotationParameterType ) );
|
||||
}
|
||||
|
||||
private Type getTypeBound(Type annotationParameterType) {
|
||||
List<Type> typeParameters = annotationParameterType.getTypeParameters();
|
||||
if ( typeParameters.size() != 1 ) {
|
||||
return annotationParameterType;
|
||||
}
|
||||
return typeParameters.get( 0 ).getTypeBound();
|
||||
}
|
||||
|
||||
private Map<Type, Integer> getParameterTypes(ElementGem eleGem) {
|
||||
Map<Type, Integer> suppliedParameterTypes = new HashMap<>();
|
||||
if ( eleGem.booleans().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( boolean.class ),
|
||||
eleGem.booleans().get().size() );
|
||||
}
|
||||
if ( eleGem.bytes().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( byte.class ),
|
||||
eleGem.bytes().get().size() );
|
||||
}
|
||||
if ( eleGem.chars().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( char.class ),
|
||||
eleGem.chars().get().size() );
|
||||
}
|
||||
if ( eleGem.classes().hasValue() ) {
|
||||
for ( TypeMirror mirror : eleGem.classes().get() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( typeMirrorFromAnnotation( mirror ) ),
|
||||
eleGem.classes().get().size()
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( eleGem.doubles().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( double.class ),
|
||||
eleGem.doubles().get().size() );
|
||||
}
|
||||
if ( eleGem.floats().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( float.class ),
|
||||
eleGem.floats().get().size() );
|
||||
}
|
||||
if ( eleGem.ints().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( int.class ),
|
||||
eleGem.ints().get().size() );
|
||||
}
|
||||
if ( eleGem.longs().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( long.class ),
|
||||
eleGem.longs().get().size() );
|
||||
}
|
||||
if ( eleGem.shorts().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( short.class ),
|
||||
eleGem.shorts().get().size() );
|
||||
}
|
||||
if ( eleGem.strings().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( String.class ),
|
||||
eleGem.strings().get().size() );
|
||||
}
|
||||
if ( eleGem.enums().hasValue() && eleGem.enumClass().hasValue() ) {
|
||||
suppliedParameterTypes.put(
|
||||
typeFactory.getType( getTypeMirror( eleGem.enumClass() ) ),
|
||||
eleGem.enums().get().size() );
|
||||
}
|
||||
return suppliedParameterTypes;
|
||||
}
|
||||
|
||||
private Type getAnnotationParameterType(Map<String, ExecutableElement> annotationParameters,
|
||||
ElementGem element) {
|
||||
if ( annotationParameters.containsKey( element.name().get() ) ) {
|
||||
return typeFactory.getType( annotationParameters.get( element.name().get() ).getReturnType() );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeMirror getTypeMirror(GemValue<TypeMirror> gemValue) {
|
||||
return typeMirrorFromAnnotation( gemValue.getValue() );
|
||||
}
|
||||
|
||||
private TypeMirror typeMirrorFromAnnotation(TypeMirror typeMirror) {
|
||||
if ( typeMirror == null ) {
|
||||
// When a class used in an annotation is created by another annotation processor
|
||||
// then javac will not return correct TypeMirror with TypeKind#ERROR, but rather a string "<error>"
|
||||
// the gem tools would return a null TypeMirror in that case.
|
||||
// Therefore, throw TypeHierarchyErroneousException so we can postpone the generation of the mapper
|
||||
throw new TypeHierarchyErroneousException( typeMirror );
|
||||
}
|
||||
|
||||
return typeMirror;
|
||||
}
|
||||
|
||||
}
|
@ -6,9 +6,11 @@
|
||||
package org.mapstruct.ap.internal.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||
import org.mapstruct.ap.internal.model.common.ModelElement;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
|
||||
@ -21,16 +23,13 @@ public class Annotation extends ModelElement {
|
||||
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* List of annotation attributes. Quite simplistic, but it's sufficient for now.
|
||||
*/
|
||||
private List<String> properties;
|
||||
private List<AnnotationElement> properties;
|
||||
|
||||
public Annotation(Type type) {
|
||||
this( type, Collections.emptyList() );
|
||||
}
|
||||
|
||||
public Annotation(Type type, List<String> properties) {
|
||||
public Annotation(Type type, List<AnnotationElement> properties) {
|
||||
this.type = type;
|
||||
this.properties = properties;
|
||||
}
|
||||
@ -41,10 +40,15 @@ public class Annotation extends ModelElement {
|
||||
|
||||
@Override
|
||||
public Set<Type> getImportTypes() {
|
||||
return Collections.singleton( type );
|
||||
Set<Type> types = new HashSet<>();
|
||||
for ( AnnotationElement prop : properties ) {
|
||||
types.addAll( prop.getImportTypes() );
|
||||
}
|
||||
types.add( type );
|
||||
return types;
|
||||
}
|
||||
|
||||
public List<String> getProperties() {
|
||||
public List<AnnotationElement> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ import static org.mapstruct.ap.internal.util.Message.PROPERTYMAPPING_CANNOT_DETE
|
||||
*/
|
||||
public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
private final List<Annotation> annotations;
|
||||
private final List<PropertyMapping> propertyMappings;
|
||||
private final Map<String, List<PropertyMapping>> mappingsByParameter;
|
||||
private final Map<String, List<PropertyMapping>> constructorMappingsByParameter;
|
||||
@ -112,6 +113,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
private final Set<Parameter> unprocessedSourceParameters = new HashSet<>();
|
||||
private final Set<String> existingVariableNames = new HashSet<>();
|
||||
private final Map<String, Set<MappingReference>> unprocessedDefinedTargets = new LinkedHashMap<>();
|
||||
private final List<Annotation> annotations = new ArrayList<>();
|
||||
|
||||
private MappingReferences mappingReferences;
|
||||
private MethodReference factoryMethod;
|
||||
@ -214,6 +216,12 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
// If the return type cannot be constructed then no need to try to create mappings
|
||||
return null;
|
||||
}
|
||||
AdditionalAnnotationsBuilder additionalAnnotationsBuilder =
|
||||
new AdditionalAnnotationsBuilder(
|
||||
ctx.getElementUtils(),
|
||||
ctx.getTypeFactory(),
|
||||
ctx.getMessager() );
|
||||
annotations.addAll( additionalAnnotationsBuilder.getProcessedAnnotations( method.getExecutable() ) );
|
||||
|
||||
/* the type that needs to be used in the mapping process as target */
|
||||
Type resultTypeToMap = returnTypeToConstruct == null ? method.getResultType() : returnTypeToConstruct;
|
||||
@ -362,6 +370,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
return new BeanMappingMethod(
|
||||
method,
|
||||
annotations,
|
||||
existingVariableNames,
|
||||
propertyMappings,
|
||||
factoryMethod,
|
||||
@ -1701,6 +1710,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
//CHECKSTYLE:OFF
|
||||
private BeanMappingMethod(Method method,
|
||||
List<Annotation> annotations,
|
||||
Collection<String> existingVariableNames,
|
||||
List<PropertyMapping> propertyMappings,
|
||||
MethodReference factoryMethod,
|
||||
@ -1722,6 +1732,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
);
|
||||
//CHECKSTYLE:ON
|
||||
|
||||
this.annotations = annotations;
|
||||
this.propertyMappings = propertyMappings;
|
||||
this.returnTypeBuilder = returnTypeBuilder;
|
||||
this.finalizerMethod = finalizerMethod;
|
||||
@ -1760,6 +1771,10 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
this.subclassMappings = subclassMappings;
|
||||
}
|
||||
|
||||
public List<Annotation> getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public List<PropertyMapping> getConstantMappings() {
|
||||
return constantMappings;
|
||||
}
|
||||
|
@ -10,15 +10,14 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import org.mapstruct.ap.internal.util.ElementUtils;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Accessibility;
|
||||
import org.mapstruct.ap.internal.model.common.ModelElement;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.internal.option.Options;
|
||||
import org.mapstruct.ap.internal.util.ElementUtils;
|
||||
import org.mapstruct.ap.internal.util.Strings;
|
||||
import org.mapstruct.ap.internal.version.VersionInformation;
|
||||
|
||||
@ -220,7 +219,9 @@ public abstract class GeneratedType extends ModelElement {
|
||||
}
|
||||
|
||||
for ( Annotation annotation : annotations ) {
|
||||
addIfImportRequired( importedTypes, annotation.getType() );
|
||||
for ( Type type : annotation.getImportTypes() ) {
|
||||
addIfImportRequired( importedTypes, type );
|
||||
}
|
||||
}
|
||||
|
||||
for ( Type extraImport : extraImportedTypes ) {
|
||||
|
@ -8,7 +8,6 @@ package org.mapstruct.ap.internal.model;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
@ -43,6 +42,7 @@ public class Mapper extends GeneratedType {
|
||||
private String implPackage;
|
||||
private boolean customPackage;
|
||||
private boolean suppressGeneratorTimestamp;
|
||||
private Set<Annotation> customAnnotations;
|
||||
|
||||
public Builder() {
|
||||
super( Builder.class );
|
||||
@ -63,6 +63,11 @@ public class Mapper extends GeneratedType {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder additionalAnnotations(Set<Annotation> customAnnotations) {
|
||||
this.customAnnotations = customAnnotations;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder decorator(Decorator decorator) {
|
||||
this.decorator = decorator;
|
||||
return this;
|
||||
@ -105,6 +110,7 @@ public class Mapper extends GeneratedType {
|
||||
definitionType,
|
||||
customPackage,
|
||||
customName,
|
||||
customAnnotations,
|
||||
methods,
|
||||
options,
|
||||
versionInformation,
|
||||
@ -126,7 +132,7 @@ public class Mapper extends GeneratedType {
|
||||
@SuppressWarnings( "checkstyle:parameternumber" )
|
||||
private Mapper(TypeFactory typeFactory, String packageName, String name,
|
||||
Type mapperDefinitionType,
|
||||
boolean customPackage, boolean customImplName,
|
||||
boolean customPackage, boolean customImplName, Set<Annotation> customAnnotations,
|
||||
List<MappingMethod> methods, Options options, VersionInformation versionInformation,
|
||||
boolean suppressGeneratorTimestamp,
|
||||
Accessibility accessibility, List<Field> fields, Constructor constructor,
|
||||
@ -148,6 +154,7 @@ public class Mapper extends GeneratedType {
|
||||
);
|
||||
this.customPackage = customPackage;
|
||||
this.customImplName = customImplName;
|
||||
customAnnotations.forEach( this::addAnnotation );
|
||||
|
||||
this.decorator = decorator;
|
||||
}
|
||||
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.internal.model.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.ModelElement;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
public class AnnotationElement extends ModelElement {
|
||||
public enum AnnotationElementType {
|
||||
BOOLEAN, BYTE, CHARACTER, CLASS, DOUBLE, ENUM, FLOAT, INTEGER, LONG, SHORT, STRING
|
||||
}
|
||||
|
||||
private final String elementName;
|
||||
private final List<? extends Object> values;
|
||||
private final AnnotationElementType type;
|
||||
|
||||
public AnnotationElement(AnnotationElementType type, List<? extends Object> values) {
|
||||
this( type, null, values );
|
||||
}
|
||||
|
||||
public AnnotationElement(AnnotationElementType type, String elementName, List<? extends Object> values) {
|
||||
this.type = type;
|
||||
this.elementName = elementName;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public String getElementName() {
|
||||
return elementName;
|
||||
}
|
||||
|
||||
public List<? extends Object> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Type> getImportTypes() {
|
||||
Set<Type> importTypes = null;
|
||||
for ( Object value : values ) {
|
||||
if ( value instanceof ModelElement ) {
|
||||
if ( importTypes == null ) {
|
||||
importTypes = new HashSet<>();
|
||||
}
|
||||
importTypes.addAll( ( (ModelElement) value ).getImportTypes() );
|
||||
}
|
||||
}
|
||||
|
||||
return importTypes == null ? Collections.emptySet() : importTypes;
|
||||
}
|
||||
|
||||
public boolean isBoolean() {
|
||||
return type == AnnotationElementType.BOOLEAN;
|
||||
}
|
||||
|
||||
public boolean isByte() {
|
||||
return type == AnnotationElementType.BYTE;
|
||||
}
|
||||
|
||||
public boolean isCharacter() {
|
||||
return type == AnnotationElementType.CHARACTER;
|
||||
}
|
||||
|
||||
public boolean isClass() {
|
||||
return type == AnnotationElementType.CLASS;
|
||||
}
|
||||
|
||||
public boolean isDouble() {
|
||||
return type == AnnotationElementType.DOUBLE;
|
||||
}
|
||||
|
||||
public boolean isEnum() {
|
||||
return type == AnnotationElementType.ENUM;
|
||||
}
|
||||
|
||||
public boolean isFloat() {
|
||||
return type == AnnotationElementType.FLOAT;
|
||||
}
|
||||
|
||||
public boolean isInteger() {
|
||||
return type == AnnotationElementType.INTEGER;
|
||||
}
|
||||
|
||||
public boolean isLong() {
|
||||
return type == AnnotationElementType.LONG;
|
||||
}
|
||||
|
||||
public boolean isShort() {
|
||||
return type == AnnotationElementType.SHORT;
|
||||
}
|
||||
|
||||
public boolean isString() {
|
||||
return type == AnnotationElementType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( elementName, type, values );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if ( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
AnnotationElement other = (AnnotationElement) obj;
|
||||
return Objects.equals( elementName, other.elementName )
|
||||
&& type == other.type
|
||||
&& Objects.equals( values, other.values );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.internal.model.annotation;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.ModelElement;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
|
||||
public class EnumAnnotationElementHolder extends ModelElement {
|
||||
|
||||
private final Type enumClass;
|
||||
private final String name;
|
||||
|
||||
public EnumAnnotationElementHolder(Type enumClass, String name) {
|
||||
this.enumClass = enumClass;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Type getEnumClass() {
|
||||
return enumClass;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Type> getImportTypes() {
|
||||
return enumClass.getImportTypes();
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@ import java.util.List;
|
||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||
@ -67,7 +69,10 @@ public class JakartaComponentProcessor extends AnnotationBasedComponentModelProc
|
||||
private Annotation namedDelegate(Mapper mapper) {
|
||||
return new Annotation(
|
||||
getTypeFactory().getType( "jakarta.inject.Named" ),
|
||||
Collections.singletonList( '"' + mapper.getPackageName() + "." + mapper.getName() + '"' )
|
||||
Collections.singletonList(
|
||||
new AnnotationElement( AnnotationElementType.STRING,
|
||||
Collections.singletonList( mapper.getPackageName() + "." + mapper.getName() )
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ import java.util.List;
|
||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.util.AnnotationProcessingException;
|
||||
|
||||
@ -70,7 +72,11 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
|
||||
private Annotation namedDelegate(Mapper mapper) {
|
||||
return new Annotation(
|
||||
getType( "Named" ),
|
||||
Collections.singletonList( '"' + mapper.getPackageName() + "." + mapper.getName() + '"' )
|
||||
Collections.singletonList(
|
||||
new AnnotationElement(
|
||||
AnnotationElementType.STRING,
|
||||
Collections.singletonList( mapper.getPackageName() + "." + mapper.getName() )
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import org.mapstruct.ap.internal.gem.InheritInverseConfigurationGem;
|
||||
import org.mapstruct.ap.internal.gem.MapperGem;
|
||||
import org.mapstruct.ap.internal.gem.MappingInheritanceStrategyGem;
|
||||
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
||||
import org.mapstruct.ap.internal.model.AdditionalAnnotationsBuilder;
|
||||
import org.mapstruct.ap.internal.model.BeanMappingMethod;
|
||||
import org.mapstruct.ap.internal.model.ContainerMappingMethod;
|
||||
import org.mapstruct.ap.internal.model.ContainerMappingMethodBuilder;
|
||||
@ -93,6 +94,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
private AccessorNamingUtils accessorNaming;
|
||||
private MappingBuilderContext mappingContext;
|
||||
|
||||
private AdditionalAnnotationsBuilder additionalAnnotationsBuilder;
|
||||
|
||||
@Override
|
||||
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<SourceMethod> sourceModel) {
|
||||
this.elementUtils = context.getElementUtils();
|
||||
@ -103,6 +106,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
this.versionInformation = context.getVersionInformation();
|
||||
this.typeFactory = context.getTypeFactory();
|
||||
this.accessorNaming = context.getAccessorNaming();
|
||||
additionalAnnotationsBuilder =
|
||||
new AdditionalAnnotationsBuilder( elementUtils, typeFactory, messager );
|
||||
|
||||
MapperOptions mapperOptions = MapperOptions.getInstanceOn( mapperTypeElement, context.getOptions() );
|
||||
List<MapperReference> mapperReferences = initReferencedMappers( mapperTypeElement, mapperOptions );
|
||||
@ -206,6 +211,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
.implName( mapperOptions.implementationName() )
|
||||
.implPackage( mapperOptions.implementationPackage() )
|
||||
.suppressGeneratorTimestamp( mapperOptions.suppressTimestampInGenerated() )
|
||||
.additionalAnnotations( additionalAnnotationsBuilder.getProcessedAnnotations( element ) )
|
||||
.build();
|
||||
|
||||
if ( !mappingContext.getForgedMethodsUnderCreation().isEmpty() ) {
|
||||
|
@ -8,13 +8,10 @@ package org.mapstruct.ap.internal.processor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
@ -54,9 +51,9 @@ import org.mapstruct.ap.internal.util.ElementUtils;
|
||||
import org.mapstruct.ap.internal.util.Executables;
|
||||
import org.mapstruct.ap.internal.util.FormattingMessager;
|
||||
import org.mapstruct.ap.internal.util.Message;
|
||||
import org.mapstruct.ap.internal.util.RepeatableAnnotations;
|
||||
import org.mapstruct.ap.internal.util.TypeUtils;
|
||||
import org.mapstruct.ap.spi.EnumTransformationStrategy;
|
||||
import org.mapstruct.tools.gem.Gem;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which retrieves a list of {@link SourceMethod}s
|
||||
@ -68,8 +65,6 @@ import org.mapstruct.tools.gem.Gem;
|
||||
*/
|
||||
public class MethodRetrievalProcessor implements ModelElementProcessor<Void, List<SourceMethod>> {
|
||||
|
||||
private static final String JAVA_LANG_ANNOTATION_PGK = "java.lang.annotation";
|
||||
private static final String ORG_MAPSTRUCT_PKG = "org.mapstruct";
|
||||
private static final String MAPPING_FQN = "org.mapstruct.Mapping";
|
||||
private static final String MAPPINGS_FQN = "org.mapstruct.Mappings";
|
||||
private static final String SUB_CLASS_MAPPING_FQN = "org.mapstruct.SubclassMapping";
|
||||
@ -280,8 +275,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
||||
typeUtils,
|
||||
typeFactory );
|
||||
|
||||
RepeatableMappings repeatableMappings = new RepeatableMappings();
|
||||
Set<MappingOptions> mappingOptions = repeatableMappings.getMappings( method, beanMappingOptions );
|
||||
Set<MappingOptions> mappingOptions = getMappings( method, beanMappingOptions );
|
||||
|
||||
IterableMappingOptions iterableMappingOptions = IterableMappingOptions.fromGem(
|
||||
IterableMappingGem.instanceOn( method ),
|
||||
@ -593,7 +587,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
||||
* @return The mappings for the given method, keyed by target property name
|
||||
*/
|
||||
private Set<MappingOptions> getMappings(ExecutableElement method, BeanMappingOptions beanMapping) {
|
||||
return new RepeatableMappings().getMappings( method, beanMapping );
|
||||
return new RepeatableMappings( beanMapping ).getProcessedAnnotations( method );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -607,173 +601,107 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
||||
private Set<SubclassMappingOptions> getSubclassMappings(List<Parameter> sourceParameters, Type resultType,
|
||||
ExecutableElement method, BeanMappingOptions beanMapping,
|
||||
SubclassValidator validator) {
|
||||
return new RepeatableSubclassMappings( sourceParameters, resultType, validator )
|
||||
.getMappings( method, beanMapping );
|
||||
return new RepeatableSubclassMappings( beanMapping, sourceParameters, resultType, validator )
|
||||
.getProcessedAnnotations( method );
|
||||
}
|
||||
|
||||
private class RepeatableMappings extends RepeatableMappingAnnotations<MappingGem, MappingsGem, MappingOptions> {
|
||||
RepeatableMappings() {
|
||||
super( MAPPING_FQN, MAPPINGS_FQN );
|
||||
private class RepeatableMappings extends RepeatableAnnotations<MappingGem, MappingsGem, MappingOptions> {
|
||||
private BeanMappingOptions beanMappingOptions;
|
||||
|
||||
RepeatableMappings(BeanMappingOptions beanMappingOptions) {
|
||||
super( elementUtils, MAPPING_FQN, MAPPINGS_FQN );
|
||||
this.beanMappingOptions = beanMappingOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
MappingGem singularInstanceOn(Element element) {
|
||||
protected MappingGem singularInstanceOn(Element element) {
|
||||
return MappingGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
MappingsGem multipleInstanceOn(Element element) {
|
||||
protected MappingsGem multipleInstanceOn(Element element) {
|
||||
return MappingsGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
void addInstance(MappingGem gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<MappingOptions> mappings) {
|
||||
MappingOptions.addInstance( gem, method, beanMappingOptions, messager, typeUtils, mappings );
|
||||
protected void addInstance(MappingGem gem, Element method, Set<MappingOptions> mappings) {
|
||||
MappingOptions.addInstance(
|
||||
gem,
|
||||
(ExecutableElement) method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings );
|
||||
}
|
||||
|
||||
@Override
|
||||
void addInstances(MappingsGem gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<MappingOptions> mappings) {
|
||||
MappingOptions.addInstances( gem, method, beanMappingOptions, messager, typeUtils, mappings );
|
||||
protected void addInstances(MappingsGem gem, Element method, Set<MappingOptions> mappings) {
|
||||
MappingOptions.addInstances(
|
||||
gem,
|
||||
(ExecutableElement) method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings );
|
||||
}
|
||||
}
|
||||
|
||||
private class RepeatableSubclassMappings
|
||||
extends RepeatableMappingAnnotations<SubclassMappingGem, SubclassMappingsGem, SubclassMappingOptions> {
|
||||
extends RepeatableAnnotations<SubclassMappingGem, SubclassMappingsGem, SubclassMappingOptions> {
|
||||
private final List<Parameter> sourceParameters;
|
||||
private final Type resultType;
|
||||
private SubclassValidator validator;
|
||||
private BeanMappingOptions beanMappingOptions;
|
||||
|
||||
RepeatableSubclassMappings(List<Parameter> sourceParameters, Type resultType, SubclassValidator validator) {
|
||||
super( SUB_CLASS_MAPPING_FQN, SUB_CLASS_MAPPINGS_FQN );
|
||||
RepeatableSubclassMappings(BeanMappingOptions beanMappingOptions, List<Parameter> sourceParameters,
|
||||
Type resultType, SubclassValidator validator) {
|
||||
super( elementUtils, SUB_CLASS_MAPPING_FQN, SUB_CLASS_MAPPINGS_FQN );
|
||||
this.beanMappingOptions = beanMappingOptions;
|
||||
this.sourceParameters = sourceParameters;
|
||||
this.resultType = resultType;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Override
|
||||
SubclassMappingGem singularInstanceOn(Element element) {
|
||||
protected SubclassMappingGem singularInstanceOn(Element element) {
|
||||
return SubclassMappingGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
SubclassMappingsGem multipleInstanceOn(Element element) {
|
||||
protected SubclassMappingsGem multipleInstanceOn(Element element) {
|
||||
return SubclassMappingsGem.instanceOn( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
void addInstance(SubclassMappingGem gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<SubclassMappingOptions> mappings) {
|
||||
SubclassMappingOptions
|
||||
.addInstance(
|
||||
gem,
|
||||
method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings,
|
||||
sourceParameters,
|
||||
resultType,
|
||||
validator );
|
||||
protected void addInstance(SubclassMappingGem gem,
|
||||
Element method,
|
||||
Set<SubclassMappingOptions> mappings) {
|
||||
SubclassMappingOptions.addInstance(
|
||||
gem,
|
||||
(ExecutableElement) method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings,
|
||||
sourceParameters,
|
||||
resultType,
|
||||
validator );
|
||||
}
|
||||
|
||||
@Override
|
||||
void addInstances(SubclassMappingsGem gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<SubclassMappingOptions> mappings) {
|
||||
SubclassMappingOptions
|
||||
.addInstances(
|
||||
gem,
|
||||
method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings,
|
||||
sourceParameters,
|
||||
resultType,
|
||||
validator );
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class RepeatableMappingAnnotations<SINGULAR extends Gem, MULTIPLE extends Gem, OPTIONS> {
|
||||
|
||||
private final String singularFqn;
|
||||
private final String multipleFqn;
|
||||
|
||||
RepeatableMappingAnnotations(String singularFqn, String multipleFqn) {
|
||||
this.singularFqn = singularFqn;
|
||||
this.multipleFqn = multipleFqn;
|
||||
}
|
||||
|
||||
abstract SINGULAR singularInstanceOn(Element element);
|
||||
|
||||
abstract MULTIPLE multipleInstanceOn(Element element);
|
||||
|
||||
abstract void addInstance(SINGULAR gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<OPTIONS> mappings);
|
||||
|
||||
abstract void addInstances(MULTIPLE gem, ExecutableElement method, BeanMappingOptions beanMappingOptions,
|
||||
Set<OPTIONS> mappings);
|
||||
|
||||
/**
|
||||
* Retrieves the mappings configured via {@code @Mapping} from the given method.
|
||||
*
|
||||
* @param method The method of interest
|
||||
* @param beanMapping options coming from bean mapping method
|
||||
* @return The mappings for the given method, keyed by target property name
|
||||
*/
|
||||
public Set<OPTIONS> getMappings(ExecutableElement method, BeanMappingOptions beanMapping) {
|
||||
return getMappings( method, method, beanMapping, new LinkedHashSet<>(), new HashSet<>() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the mappings configured via {@code @Mapping} from the given method.
|
||||
*
|
||||
* @param method The method of interest
|
||||
* @param element Element of interest: method, or (meta) annotation
|
||||
* @param beanMapping options coming from bean mapping method
|
||||
* @param mappingOptions LinkedSet of mappings found so far
|
||||
* @return The mappings for the given method, keyed by target property name
|
||||
*/
|
||||
private Set<OPTIONS> getMappings(ExecutableElement method, Element element,
|
||||
BeanMappingOptions beanMapping, LinkedHashSet<OPTIONS> mappingOptions,
|
||||
Set<Element> handledElements) {
|
||||
|
||||
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
|
||||
Element lElement = annotationMirror.getAnnotationType().asElement();
|
||||
if ( isAnnotation( lElement, singularFqn ) ) {
|
||||
// although getInstanceOn does a search on annotation mirrors, the order is preserved
|
||||
SINGULAR mapping = singularInstanceOn( element );
|
||||
addInstance( mapping, method, beanMapping, mappingOptions );
|
||||
}
|
||||
else if ( isAnnotation( lElement, multipleFqn ) ) {
|
||||
// although getInstanceOn does a search on annotation mirrors, the order is preserved
|
||||
MULTIPLE mappings = multipleInstanceOn( element );
|
||||
addInstances( mappings, method, beanMapping, mappingOptions );
|
||||
}
|
||||
else if ( !isAnnotationInPackage( lElement, JAVA_LANG_ANNOTATION_PGK )
|
||||
&& !isAnnotationInPackage( lElement, ORG_MAPSTRUCT_PKG )
|
||||
&& !handledElements.contains( lElement ) ) {
|
||||
// recur over annotation mirrors
|
||||
handledElements.add( lElement );
|
||||
getMappings( method, lElement, beanMapping, mappingOptions, handledElements );
|
||||
}
|
||||
}
|
||||
return mappingOptions;
|
||||
}
|
||||
|
||||
private boolean isAnnotationInPackage(Element element, String packageFQN) {
|
||||
if ( ElementKind.ANNOTATION_TYPE == element.getKind() ) {
|
||||
return packageFQN.equals( elementUtils.getPackageOf( element ).getQualifiedName().toString() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAnnotation(Element element, String annotationFQN) {
|
||||
if ( ElementKind.ANNOTATION_TYPE == element.getKind() ) {
|
||||
return annotationFQN.equals( ( (TypeElement) element ).getQualifiedName().toString() );
|
||||
}
|
||||
return false;
|
||||
protected void addInstances(SubclassMappingsGem gem,
|
||||
Element method,
|
||||
Set<SubclassMappingOptions> mappings) {
|
||||
SubclassMappingOptions.addInstances(
|
||||
gem,
|
||||
(ExecutableElement) method,
|
||||
beanMappingOptions,
|
||||
messager,
|
||||
typeUtils,
|
||||
mappings,
|
||||
sourceParameters,
|
||||
resultType,
|
||||
validator );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ import java.util.List;
|
||||
import org.mapstruct.ap.internal.gem.MappingConstantsGem;
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement;
|
||||
import org.mapstruct.ap.internal.model.annotation.AnnotationElement.AnnotationElementType;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||
@ -75,7 +77,11 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
||||
private Annotation qualifierDelegate() {
|
||||
return new Annotation(
|
||||
getTypeFactory().getType( "org.springframework.beans.factory.annotation.Qualifier" ),
|
||||
Collections.singletonList( "\"delegate\"" ) );
|
||||
Collections.singletonList(
|
||||
new AnnotationElement(
|
||||
AnnotationElementType.STRING,
|
||||
Collections.singletonList( "delegate" )
|
||||
) ) );
|
||||
}
|
||||
|
||||
private Annotation primary() {
|
||||
|
@ -198,6 +198,20 @@ public enum Message {
|
||||
|
||||
MAPTOBEANMAPPING_WRONG_KEY_TYPE( "The Map parameter \"%s\" cannot be used for property mapping. It must be typed with Map<String, ???> but it was typed with %s.", Diagnostic.Kind.WARNING ),
|
||||
MAPTOBEANMAPPING_RAW_MAP( "The Map parameter \"%s\" cannot be used for property mapping. It must be typed with Map<String, ???> but it was raw.", Diagnostic.Kind.WARNING ),
|
||||
|
||||
ANNOTATE_WITH_MISSING_REQUIRED_PARAMETER( "Parameter \"%s\" is required for annotation \"%s\"." ),
|
||||
ANNOTATE_WITH_UNKNOWN_PARAMETER( "Unknown parameter \"%s\" for annotation \"%s\". Did you mean \"%s\"?" ),
|
||||
ANNOTATE_WITH_DUPLICATE_PARAMETER( "Parameter \"%s\" must not be defined more than once." ),
|
||||
ANNOTATE_WITH_WRONG_PARAMETER( "Parameter \"%s\" is not of type \"%s\" but of type \"%s\" for annotation \"%s\"." ),
|
||||
ANNOTATE_WITH_TOO_MANY_VALUE_TYPES( "Parameter \"%s\" has too many value types supplied, type \"%s\" is expected for annotation \"%s\"." ),
|
||||
ANNOTATE_WITH_PARAMETER_ARRAY_NOT_EXPECTED( "Parameter \"%s\" does not accept multiple values for annotation \"%s\"." ),
|
||||
ANNOTATE_WITH_NOT_ALLOWED_ON_CLASS( "Annotation \"%s\" is not allowed on classes." ),
|
||||
ANNOTATE_WITH_NOT_ALLOWED_ON_METHODS( "Annotation \"%s\" is not allowed on methods." ),
|
||||
ANNOTATE_WITH_ENUM_VALUE_DOES_NOT_EXIST( "Enum \"%s\" does not have value \"%s\"." ),
|
||||
ANNOTATE_WITH_ENUM_CLASS_NOT_DEFINED( "enumClass needs to be defined when using enums." ),
|
||||
ANNOTATE_WITH_ENUMS_NOT_DEFINED( "enums needs to be defined when using enumClass." ),
|
||||
ANNOTATE_WITH_ANNOTATION_IS_NOT_REPEATABLE( "Annotation \"%s\" is not repeatable." ),
|
||||
ANNOTATE_WITH_DUPLICATE( "Annotation \"%s\" is already present with the same elements configuration.", Diagnostic.Kind.WARNING ),
|
||||
;
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.internal.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import org.mapstruct.tools.gem.Gem;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
public abstract class RepeatableAnnotations<SINGULAR extends Gem, MULTIPLE extends Gem, OPTIONS> {
|
||||
private static final String JAVA_LANG_ANNOTATION_PGK = "java.lang.annotation";
|
||||
private static final String ORG_MAPSTRUCT_PKG = "org.mapstruct";
|
||||
|
||||
private ElementUtils elementUtils;
|
||||
private final String singularFqn;
|
||||
private final String multipleFqn;
|
||||
|
||||
protected RepeatableAnnotations(ElementUtils elementUtils, String singularFqn, String multipleFqn) {
|
||||
this.elementUtils = elementUtils;
|
||||
this.singularFqn = singularFqn;
|
||||
this.multipleFqn = multipleFqn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param element the element on which the Gem needs to be found
|
||||
* @return the Gem found on the element.
|
||||
*/
|
||||
protected abstract SINGULAR singularInstanceOn(Element element);
|
||||
|
||||
/**
|
||||
* @param element the element on which the Gems needs to be found
|
||||
* @return the Gems found on the element.
|
||||
*/
|
||||
protected abstract MULTIPLE multipleInstanceOn(Element element);
|
||||
|
||||
/**
|
||||
* @param gem the annotation gem to be processed
|
||||
* @param source the source element where the request originated from
|
||||
* @param mappings the collection of completed processing
|
||||
*/
|
||||
protected abstract void addInstance(SINGULAR gem, Element source, Set<OPTIONS> mappings);
|
||||
|
||||
/**
|
||||
* @param gems the annotation gems to be processed
|
||||
* @param source the source element where the request originated from
|
||||
* @param mappings the collection of completed processing
|
||||
*/
|
||||
protected abstract void addInstances(MULTIPLE gems, Element source, Set<OPTIONS> mappings);
|
||||
|
||||
/**
|
||||
* Retrieves the processed annotations.
|
||||
*
|
||||
* @param source The source element of interest
|
||||
* @return The processed annotations for the given element
|
||||
*/
|
||||
public Set<OPTIONS> getProcessedAnnotations(Element source) {
|
||||
return getMappings( source, source, new LinkedHashSet<>(), new HashSet<>() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the processed annotations.
|
||||
*
|
||||
* @param source The source element of interest
|
||||
* @param element Element of interest: method, or (meta) annotation
|
||||
* @param mappingOptions LinkedSet of mappings found so far
|
||||
* @param handledElements The collection of already handled elements to handle recursion correctly.
|
||||
* @return The processed annotations for the given element
|
||||
*/
|
||||
private Set<OPTIONS> getMappings(Element source, Element element,
|
||||
LinkedHashSet<OPTIONS> mappingOptions,
|
||||
Set<Element> handledElements) {
|
||||
|
||||
for ( AnnotationMirror annotationMirror : element.getAnnotationMirrors() ) {
|
||||
Element lElement = annotationMirror.getAnnotationType().asElement();
|
||||
if ( isAnnotation( lElement, singularFqn ) ) {
|
||||
// although getInstanceOn does a search on annotation mirrors, the order is preserved
|
||||
SINGULAR mapping = singularInstanceOn( element );
|
||||
addInstance( mapping, source, mappingOptions );
|
||||
}
|
||||
else if ( isAnnotation( lElement, multipleFqn ) ) {
|
||||
// although getInstanceOn does a search on annotation mirrors, the order is preserved
|
||||
MULTIPLE mappings = multipleInstanceOn( element );
|
||||
addInstances( mappings, source, mappingOptions );
|
||||
}
|
||||
else if ( !isAnnotationInPackage( lElement, JAVA_LANG_ANNOTATION_PGK )
|
||||
&& !isAnnotationInPackage( lElement, ORG_MAPSTRUCT_PKG )
|
||||
&& !handledElements.contains( lElement ) ) {
|
||||
// recur over annotation mirrors
|
||||
handledElements.add( lElement );
|
||||
getMappings( source, lElement, mappingOptions, handledElements );
|
||||
}
|
||||
}
|
||||
return mappingOptions;
|
||||
}
|
||||
|
||||
private boolean isAnnotationInPackage(Element element, String packageFQN) {
|
||||
if ( ElementKind.ANNOTATION_TYPE == element.getKind() ) {
|
||||
return packageFQN.equals( elementUtils.getPackageOf( element ).getQualifiedName().toString() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAnnotation(Element element, String annotationFQN) {
|
||||
if ( ElementKind.ANNOTATION_TYPE == element.getKind() ) {
|
||||
return annotationFQN.equals( ( (TypeElement) element ).getQualifiedName().toString() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -6,4 +6,4 @@
|
||||
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.Annotation" -->
|
||||
@<@includeModel object=type/><#if (properties?size > 0) >(<#list properties as property>${property}<#if property_has_next>, </#if></#list>)</#if>
|
||||
@<@includeModel object=type/><#if (properties?size > 0) >(<#list properties as property><@includeModel object=property/><#if property_has_next>, </#if></#list>)</#if>
|
@ -6,6 +6,9 @@
|
||||
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.BeanMappingMethod" -->
|
||||
<#list annotations as annotation>
|
||||
<#nt><@includeModel object=annotation/>
|
||||
</#list>
|
||||
<#if overridden>@Override</#if>
|
||||
<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, </#if></#list>)<@throws/> {
|
||||
<#assign targetType = resultType />
|
||||
|
@ -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
|
||||
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.annotation.AnnotationElement" -->
|
||||
<@compress single_line=true>
|
||||
<#if elementName??>
|
||||
${elementName} =
|
||||
</#if>
|
||||
<#if (values?size > 1) >
|
||||
{
|
||||
</#if>
|
||||
<#-- rt and lt tags below are for formatting the arrays so that there are no spaces before ',' -->
|
||||
<#list values as value>
|
||||
<#if boolean>
|
||||
${value?c}<#rt>
|
||||
<#elseif byte>
|
||||
${value}<#rt>
|
||||
<#elseif character>
|
||||
'${value}'<#rt>
|
||||
<#elseif class>
|
||||
<@includeModel object=value raw=true/>.class<#rt>
|
||||
<#elseif double>
|
||||
${value?c}<#rt>
|
||||
<#elseif enum>
|
||||
<@includeModel object=value/><#rt>
|
||||
<#elseif float>
|
||||
${value?c}f<#rt>
|
||||
<#elseif integer>
|
||||
${value?c}<#rt>
|
||||
<#elseif long>
|
||||
${value?c}L<#rt>
|
||||
<#elseif short>
|
||||
${value?c}<#rt>
|
||||
<#elseif string>
|
||||
"${value}"<#rt>
|
||||
</#if>
|
||||
<#if value_has_next>
|
||||
, <#lt>
|
||||
</#if>
|
||||
</#list>
|
||||
<#if (values?size > 1) >
|
||||
}
|
||||
</#if>
|
||||
</@compress>
|
@ -0,0 +1,9 @@
|
||||
<#--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.annotation.EnumAnnotationElementHolder" -->
|
||||
<@includeModel object=enumClass raw=true/>.${name}<#rt>
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public enum AnnotateWithEnum {
|
||||
EXISTING, OTHER_EXISTING
|
||||
}
|
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
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.ap.testutil.runner.GeneratedSource;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@IssueKey("1574")
|
||||
@WithClasses(AnnotateWithEnum.class)
|
||||
public class AnnotateWithTest {
|
||||
|
||||
@RegisterExtension
|
||||
final GeneratedSource generatedSource = new GeneratedSource();
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses({ DeprecateAndCustomMapper.class, CustomAnnotation.class })
|
||||
public void mapperBecomesDeprecatedAndGetsCustomAnnotation() {
|
||||
DeprecateAndCustomMapper mapper = Mappers.getMapper( DeprecateAndCustomMapper.class );
|
||||
|
||||
assertThat( mapper.getClass() ).hasAnnotations( Deprecated.class, CustomAnnotation.class );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { CustomNamedMapper.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void annotationWithValue() {
|
||||
generatedSource.addComparisonToFixtureFor( CustomNamedMapper.class );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { MultipleArrayValuesMapper.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void annotationWithMultipleValues() {
|
||||
generatedSource.addComparisonToFixtureFor( MultipleArrayValuesMapper.class );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { CustomNamedGenericClassMapper.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void annotationWithCorrectGenericClassValue() {
|
||||
CustomNamedGenericClassMapper mapper = Mappers.getMapper( CustomNamedGenericClassMapper.class );
|
||||
|
||||
CustomAnnotationWithParams annotation = mapper.getClass().getAnnotation( CustomAnnotationWithParams.class );
|
||||
assertThat( annotation ).isNotNull();
|
||||
assertThat( annotation.stringParam() ).isEqualTo( "test" );
|
||||
assertThat( annotation.genericTypedClass() ).isEqualTo( Mapper.class );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { AnnotationWithoutElementNameMapper.class, CustomAnnotation.class } )
|
||||
public void annotateWithoutElementName() {
|
||||
generatedSource
|
||||
.forMapper( AnnotationWithoutElementNameMapper.class )
|
||||
.content()
|
||||
.contains( "@CustomAnnotation(value = \"value\")" );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses({ MetaAnnotatedMapper.class, ClassMetaAnnotation.class, CustomClassOnlyAnnotation.class })
|
||||
public void metaAnnotationWorks() {
|
||||
MetaAnnotatedMapper mapper = Mappers.getMapper( MetaAnnotatedMapper.class );
|
||||
|
||||
assertThat( mapper.getClass() ).hasAnnotation( CustomClassOnlyAnnotation.class );
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithMissingParameter.class,
|
||||
line = 15,
|
||||
message = "Parameter \"required\" is required for annotation \"AnnotationWithRequiredParameter\"."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithMissingParameter.class, AnnotationWithRequiredParameter.class })
|
||||
public void erroneousMapperWithMissingParameter() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithMethodOnInterface.class,
|
||||
line = 15,
|
||||
message = "Annotation \"CustomMethodOnlyAnnotation\" is not allowed on classes."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithMethodOnInterface.class, CustomMethodOnlyAnnotation.class })
|
||||
public void erroneousMapperWithMethodOnInterface() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithMethodOnClass.class,
|
||||
line = 15,
|
||||
message = "Annotation \"CustomMethodOnlyAnnotation\" is not allowed on classes."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithMethodOnClass.class, CustomMethodOnlyAnnotation.class })
|
||||
public void erroneousMapperWithMethodOnClass() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithAnnotationOnlyOnInterface.class,
|
||||
line = 15,
|
||||
message = "Annotation \"CustomAnnotationOnlyAnnotation\" is not allowed on classes."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithAnnotationOnlyOnInterface.class, CustomAnnotationOnlyAnnotation.class })
|
||||
public void erroneousMapperWithAnnotationOnlyOnInterface() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithAnnotationOnlyOnClass.class,
|
||||
line = 15,
|
||||
message = "Annotation \"CustomAnnotationOnlyAnnotation\" is not allowed on classes."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithAnnotationOnlyOnClass.class, CustomAnnotationOnlyAnnotation.class })
|
||||
public void erroneousMapperWithAnnotationOnlyOnClass() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithClassOnMethod.class,
|
||||
line = 17,
|
||||
message = "Annotation \"CustomClassOnlyAnnotation\" is not allowed on methods."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithClassOnMethod.class, CustomClassOnlyAnnotation.class })
|
||||
public void erroneousMapperWithClassOnMethod() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithUnknownParameter.class,
|
||||
line = 17,
|
||||
message = "Unknown parameter \"unknownParameter\" for annotation \"CustomAnnotation\"." +
|
||||
" Did you mean \"value\"?"
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({ ErroneousMapperWithUnknownParameter.class, CustomAnnotation.class })
|
||||
public void erroneousMapperWithUnknownParameter() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithNonExistantEnum.class,
|
||||
line = 17,
|
||||
message = "Enum \"AnnotateWithEnum\" does not have value \"NON_EXISTANT\"."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithNonExistantEnum.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperWithNonExistantEnum() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithTooManyParameterValues.class,
|
||||
line = 17,
|
||||
message = "Parameter \"stringParam\" has too many value types supplied, type \"String\" is expected"
|
||||
+ " for annotation \"CustomAnnotationWithParams\"."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithTooManyParameterValues.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperWithTooManyParameterValues() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 16,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"boolean\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 18,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"byte\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 20,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"char\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 22,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"CustomAnnotationWithParams\""
|
||||
+ " but of type \"String\" for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 24,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"double\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 26,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"float\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 28,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"int\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 30,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"long\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 32,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" is not of type \"short\" but of type \"String\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 35,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"genericTypedClass\" is not of type \"String\" "
|
||||
+ "but of type \"Class<? extends java.lang.annotation.Annotation>\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 36,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"enumParam\" is not of type \"WrongAnnotateWithEnum\" "
|
||||
+ "but of type \"AnnotateWithEnum\" for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 40,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"genericTypedClass\" is not of type \"ErroneousMapperWithWrongParameter\" "
|
||||
+ "but of type \"Class<? extends java.lang.annotation.Annotation>\" "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithWrongParameter.class,
|
||||
line = 42,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"value\" is not of type \"boolean\" "
|
||||
+ "but of type \"String\" for annotation \"CustomAnnotation\"."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses({
|
||||
ErroneousMapperWithWrongParameter.class, CustomAnnotationWithParams.class,
|
||||
CustomAnnotationWithParamsContainer.class, WrongAnnotateWithEnum.class, CustomAnnotation.class
|
||||
})
|
||||
public void erroneousMapperWithWrongParameter() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 17,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"stringParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 18,
|
||||
alternativeLine = 43,
|
||||
message = "Parameter \"booleanParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 19,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"byteParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 20,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"charParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 21,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"doubleParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 22,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"floatParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 23,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"intParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 24,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"longParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 25,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"shortParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 26,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"genericTypedClass\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
),
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMultipleArrayValuesMapper.class,
|
||||
line = 27,
|
||||
alternativeLine = 32,
|
||||
message = "Parameter \"enumParam\" does not accept multiple values "
|
||||
+ "for annotation \"CustomAnnotationWithParams\"."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMultipleArrayValuesMapper.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperUsingMultipleValuesInsteadOfSingle() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { MapperWithMissingAnnotationElementName.class,
|
||||
CustomAnnotationWithTwoAnnotationElements.class } )
|
||||
public void mapperWithMissingAnnotationElementNameShouldCompile() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithMissingEnumClass.class,
|
||||
line = 17,
|
||||
message = "enumClass needs to be defined when using enums."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithMissingEnumClass.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperWithMissingEnumClass() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithMissingEnums.class,
|
||||
line = 17,
|
||||
message = "enums needs to be defined when using enumClass."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithMissingEnums.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperWithMissingEnums() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithRepeatOfNotRepeatableAnnotation.class,
|
||||
line = 16,
|
||||
alternativeLine = 17,
|
||||
message = "Annotation \"CustomAnnotation\" is not repeatable."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithRepeatOfNotRepeatableAnnotation.class, CustomAnnotation.class } )
|
||||
public void erroneousMapperWithRepeatOfNotRepeatableAnnotation() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@WithClasses( { MapperWithRepeatableAnnotation.class, CustomRepeatableAnnotation.class,
|
||||
CustomRepeatableAnnotationContainer.class } )
|
||||
public void mapperWithRepeatableAnnotationShouldCompile() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
type = ErroneousMapperWithParameterRepeat.class,
|
||||
line = 18,
|
||||
message = "Parameter \"stringParam\" must not be defined more than once."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { ErroneousMapperWithParameterRepeat.class, CustomAnnotationWithParamsContainer.class,
|
||||
CustomAnnotationWithParams.class } )
|
||||
public void erroneousMapperWithParameterRepeat() {
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.SUCCEEDED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
kind = javax.tools.Diagnostic.Kind.WARNING,
|
||||
type = MapperWithIdenticalAnnotationRepeated.class,
|
||||
line = 16,
|
||||
alternativeLine = 17,
|
||||
message = "Annotation \"CustomRepeatableAnnotation\" is already present "
|
||||
+ "with the same elements configuration."
|
||||
)
|
||||
}
|
||||
)
|
||||
@WithClasses( { MapperWithIdenticalAnnotationRepeated.class, CustomRepeatableAnnotation.class,
|
||||
CustomRepeatableAnnotationContainer.class } )
|
||||
public void mapperWithIdenticalAnnotationRepeated() {
|
||||
}
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface AnnotationWithRequiredParameter {
|
||||
String required();
|
||||
}
|
@ -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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotation.class, elements = @AnnotateWith.Element( strings = "value" ) )
|
||||
public interface AnnotationWithoutElementNameMapper {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( { ElementType.TYPE } )
|
||||
@AnnotateWith( CustomClassOnlyAnnotation.class )
|
||||
public @interface ClassMetaAnnotation {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface CustomAnnotation {
|
||||
String value() default "";
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@Target({ ANNOTATION_TYPE })
|
||||
public @interface CustomAnnotationOnlyAnnotation {
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { METHOD, TYPE } )
|
||||
@Repeatable( CustomAnnotationWithParamsContainer.class )
|
||||
public @interface CustomAnnotationWithParams {
|
||||
String stringParam();
|
||||
|
||||
Class<? extends Annotation> genericTypedClass() default CustomAnnotationWithParams.class;
|
||||
|
||||
AnnotateWithEnum enumParam() default AnnotateWithEnum.EXISTING;
|
||||
|
||||
byte byteParam() default 0x00;
|
||||
|
||||
char charParam() default 'a';
|
||||
|
||||
double doubleParam() default 0.0;
|
||||
|
||||
float floatParam() default 0.0f;
|
||||
|
||||
int intParam() default 0;
|
||||
|
||||
long longParam() default 0L;
|
||||
|
||||
short shortParam() default 0;
|
||||
|
||||
boolean booleanParam() default false;
|
||||
|
||||
short[] shortArray() default {};
|
||||
|
||||
byte[] byteArray() default {};
|
||||
|
||||
int[] intArray() default {};
|
||||
|
||||
long[] longArray() default {};
|
||||
|
||||
float[] floatArray() default {};
|
||||
|
||||
double[] doubleArray() default {};
|
||||
|
||||
char[] charArray() default {};
|
||||
|
||||
boolean[] booleanArray() default {};
|
||||
|
||||
String[] stringArray() default {};
|
||||
|
||||
Class<?>[] classArray() default {};
|
||||
|
||||
AnnotateWithEnum[] enumArray() default {};
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface CustomAnnotationWithParamsContainer {
|
||||
CustomAnnotationWithParams[] value() default {};
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface CustomAnnotationWithTwoAnnotationElements {
|
||||
String value() default "";
|
||||
boolean namedAnnotationElement() default false;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE } )
|
||||
public @interface CustomClassOnlyAnnotation {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { METHOD } )
|
||||
public @interface CustomMethodOnlyAnnotation {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@Element( name = "stringParam", strings = "test" ),
|
||||
@Element( name = "genericTypedClass", classes = Mapper.class )
|
||||
} )
|
||||
public interface CustomNamedGenericClassMapper {
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@Element( name = "stringArray", strings = "test" ),
|
||||
@Element( name = "stringParam", strings = "test" ),
|
||||
@Element( name = "booleanArray", booleans = true ),
|
||||
@Element( name = "booleanParam", booleans = true ),
|
||||
@Element( name = "byteArray", bytes = 0x10 ),
|
||||
@Element( name = "byteParam", bytes = 0x13 ),
|
||||
@Element( name = "charArray", chars = 'd' ),
|
||||
@Element( name = "charParam", chars = 'a' ),
|
||||
@Element( name = "enumArray", enumClass = AnnotateWithEnum.class, enums = "EXISTING" ),
|
||||
@Element( name = "enumParam", enumClass = AnnotateWithEnum.class, enums = "EXISTING" ),
|
||||
@Element( name = "doubleArray", doubles = 0.3 ),
|
||||
@Element( name = "doubleParam", doubles = 1.2 ),
|
||||
@Element( name = "floatArray", floats = 0.3f ),
|
||||
@Element( name = "floatParam", floats = 1.2f ),
|
||||
@Element( name = "intArray", ints = 3 ),
|
||||
@Element( name = "intParam", ints = 1 ),
|
||||
@Element( name = "longArray", longs = 3L ),
|
||||
@Element( name = "longParam", longs = 1L ),
|
||||
@Element( name = "shortArray", shorts = 3 ),
|
||||
@Element( name = "shortParam", shorts = 1 )
|
||||
} )
|
||||
public interface CustomNamedMapper {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
@Repeatable( CustomRepeatableAnnotationContainer.class )
|
||||
public @interface CustomRepeatableAnnotation {
|
||||
String value() default "";
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Retention( RUNTIME )
|
||||
@Target( { TYPE, METHOD } )
|
||||
public @interface CustomRepeatableAnnotationContainer {
|
||||
CustomRepeatableAnnotation[] value() default {};
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( Deprecated.class )
|
||||
@AnnotateWith( CustomAnnotation.class )
|
||||
public interface DeprecateAndCustomMapper {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationOnlyAnnotation.class )
|
||||
public abstract class ErroneousMapperWithAnnotationOnlyOnClass {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationOnlyAnnotation.class )
|
||||
public interface ErroneousMapperWithAnnotationOnlyOnInterface {
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
public interface ErroneousMapperWithClassOnMethod {
|
||||
|
||||
@AnnotateWith( value = CustomClassOnlyAnnotation.class )
|
||||
Target toString(Source value);
|
||||
|
||||
class Source {
|
||||
|
||||
}
|
||||
|
||||
class Target {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomMethodOnlyAnnotation.class )
|
||||
public abstract class ErroneousMapperWithMethodOnClass {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomMethodOnlyAnnotation.class )
|
||||
public interface ErroneousMapperWithMethodOnInterface {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = { @Element( name = "enumParam", enums = "EXISTING" ),
|
||||
@Element( name = "stringParam", strings = "required" ) }
|
||||
)
|
||||
public interface ErroneousMapperWithMissingEnumClass {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @Element( name = "stringParam", strings = "required", enumClass = AnnotateWithEnum.class )
|
||||
)
|
||||
public interface ErroneousMapperWithMissingEnums {
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( AnnotationWithRequiredParameter.class )
|
||||
public interface ErroneousMapperWithMissingParameter {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = { @Element( name = "enumParam", enumClass = AnnotateWithEnum.class, enums = "NON_EXISTANT" ),
|
||||
@Element( name = "stringParam", strings = "required" ) }
|
||||
)
|
||||
public interface ErroneousMapperWithNonExistantEnum {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@Element( name = "stringParam", strings = "test" ),
|
||||
@Element( name = "stringParam", strings = "otherValue" )
|
||||
} )
|
||||
public interface ErroneousMapperWithParameterRepeat {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotation.class )
|
||||
@AnnotateWith( value = CustomAnnotation.class )
|
||||
public interface ErroneousMapperWithRepeatOfNotRepeatableAnnotation {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @Element( name = "stringParam", booleans = true, strings = "test" )
|
||||
)
|
||||
public interface ErroneousMapperWithTooManyParameterValues {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotation.class,
|
||||
elements = @Element( name = "unknownParameter", strings = "unknown" )
|
||||
)
|
||||
public interface ErroneousMapperWithUnknownParameter {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", booleans = true ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", bytes = 0x12 ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", chars = 'a' ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", classes = CustomAnnotationWithParams.class ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", doubles = 12.34 ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", floats = 12.34f ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", ints = 1234 ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", longs = 1234L ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class,
|
||||
elements = @AnnotateWith.Element( name = "stringParam", shorts = 12 ) )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@AnnotateWith.Element( name = "stringParam", strings = "correctValue" ),
|
||||
@AnnotateWith.Element( name = "genericTypedClass", strings = "wrong" ),
|
||||
@AnnotateWith.Element( name = "enumParam", enumClass = WrongAnnotateWithEnum.class, enums = "EXISTING" )
|
||||
} )
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@AnnotateWith.Element( name = "stringParam", strings = "correctValue" ),
|
||||
@AnnotateWith.Element( name = "genericTypedClass", classes = ErroneousMapperWithWrongParameter.class )
|
||||
} )
|
||||
@AnnotateWith( value = CustomAnnotation.class, elements = @AnnotateWith.Element( booleans = true ) )
|
||||
public interface ErroneousMapperWithWrongParameter {
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@Element( name = "stringParam", strings = { "test1", "test2" } ),
|
||||
@Element( name = "booleanParam", booleans = { false, true } ),
|
||||
@Element( name = "byteParam", bytes = { 0x08, 0x1f } ),
|
||||
@Element( name = "charParam", chars = { 'b', 'c' } ),
|
||||
@Element( name = "doubleParam", doubles = { 1.2, 3.4 } ),
|
||||
@Element( name = "floatParam", floats = { 1.2f, 3.4f } ),
|
||||
@Element( name = "intParam", ints = { 12, 34 } ),
|
||||
@Element( name = "longParam", longs = { 12L, 34L } ),
|
||||
@Element( name = "shortParam", shorts = { 12, 34 } ),
|
||||
@Element( name = "genericTypedClass", classes = { Mapper.class, CustomAnnotationWithParams.class } ),
|
||||
@Element( name = "enumParam", enumClass = AnnotateWithEnum.class, enums = { "EXISTING", "OTHER_EXISTING" } )
|
||||
} )
|
||||
public interface ErroneousMultipleArrayValuesMapper {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomRepeatableAnnotation.class, elements = @AnnotateWith.Element( strings = "identical" ) )
|
||||
@AnnotateWith( value = CustomRepeatableAnnotation.class, elements = @AnnotateWith.Element( strings = "identical" ) )
|
||||
public interface MapperWithIdenticalAnnotationRepeated {
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithTwoAnnotationElements.class, elements = {
|
||||
@AnnotateWith.Element( strings = "unnamed annotation element" ),
|
||||
@AnnotateWith.Element( name = "namedAnnotationElement", booleans = false )
|
||||
} )
|
||||
public abstract class MapperWithMissingAnnotationElementName {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomRepeatableAnnotation.class )
|
||||
@AnnotateWith( value = CustomRepeatableAnnotation.class, elements = @AnnotateWith.Element( strings = "different" ) )
|
||||
public interface MapperWithRepeatableAnnotation {
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@ClassMetaAnnotation
|
||||
@Mapper
|
||||
public interface MetaAnnotatedMapper {
|
||||
|
||||
}
|
@ -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.annotatewith;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( { ElementType.METHOD } )
|
||||
@AnnotateWith( CustomMethodOnlyAnnotation.class )
|
||||
public @interface MethodMetaAnnotation {
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.mapstruct.AnnotateWith;
|
||||
import org.mapstruct.AnnotateWith.Element;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* @author Ben Zegveld
|
||||
*/
|
||||
@Mapper
|
||||
@AnnotateWith( value = CustomAnnotationWithParams.class, elements = {
|
||||
@Element( name = "stringArray", strings = { "test1", "test2" } ),
|
||||
@Element( name = "booleanArray", booleans = { false, true } ),
|
||||
@Element( name = "byteArray", bytes = { 0x08, 0x1f } ),
|
||||
@Element( name = "charArray", chars = { 'b', 'c' } ),
|
||||
@Element( name = "doubleArray", doubles = { 1.2, 3.4 } ),
|
||||
@Element( name = "floatArray", floats = { 1.2f, 3.4f } ),
|
||||
@Element( name = "intArray", ints = { 12, 34 } ),
|
||||
@Element( name = "longArray", longs = { 12L, 34L } ),
|
||||
@Element( name = "shortArray", shorts = { 12, 34 } ),
|
||||
@Element( name = "classArray", classes = { Mapper.class, CustomAnnotationWithParams.class } ),
|
||||
@Element( name = "stringParam", strings = "required parameter" )
|
||||
} )
|
||||
public interface MultipleArrayValuesMapper {
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public enum WrongAnnotateWithEnum {
|
||||
EXISTING
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.annotation.processing.Generated;
|
||||
|
||||
@Generated(
|
||||
value = "org.mapstruct.ap.MappingProcessor",
|
||||
date = "2022-06-06T16:48:18+0200",
|
||||
comments = "version: , compiler: javac, environment: Java 11.0.12 (Azul Systems, Inc.)"
|
||||
)
|
||||
@CustomAnnotationWithParams(stringArray = "test", stringParam = "test", booleanArray = true, booleanParam = true, byteArray = 16, byteParam = 19, charArray = 'd', charParam = 'a', enumArray = AnnotateWithEnum.EXISTING, enumParam = AnnotateWithEnum.EXISTING, doubleArray = 0.3, doubleParam = 1.2, floatArray = 0.300000011920929f, floatParam = 1.2000000476837158f, intArray = 3, intParam = 1, longArray = 3L, longParam = 1L, shortArray = 3, shortParam = 1)
|
||||
public class CustomNamedMapperImpl implements CustomNamedMapper {
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.annotation.processing.Generated;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Generated(
|
||||
value = "org.mapstruct.ap.MappingProcessor",
|
||||
date = "2022-06-06T16:48:23+0200",
|
||||
comments = "version: , compiler: javac, environment: Java 11.0.12 (Azul Systems, Inc.)"
|
||||
)
|
||||
@CustomAnnotationWithParams(stringArray = { "test1", "test2" }, booleanArray = { false, true }, byteArray = { 8, 31 }, charArray = { 'b', 'c' }, doubleArray = { 1.2, 3.4 }, floatArray = { 1.2000000476837158f, 3.4000000953674316f }, intArray = { 12, 34 }, longArray = { 12L, 34L }, shortArray = { 12, 34 }, classArray = { Mapper.class, CustomAnnotationWithParams.class }, stringParam = "required parameter")
|
||||
public class MultipleArrayValuesMapperImpl implements MultipleArrayValuesMapper {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user