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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/src/main/java/org/mapstruct/tools/gem/GemDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@
* @return the annotation for which a Gem should be generated
*/
Class<?> value();

/**
* Specifies the name of the implementation class. The {@code <CLASS_NAME>} will be replaced by the
* interface/abstract class name.
* <p>
* Defaults to postfixing the name with {@code Gem}: {@code <CLASS_NAME>Gem}
*
* @return The implementation name.
*/
String implementationName() default "<CLASS_NAME>Gem";
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ public class GemInfo {
private final List<GemValueInfo> gemValueInfos;
private final Element[] originatingElements;

public GemInfo(String gemPackageName, String annotationName, String annotationFqn,
public GemInfo(String gemPackageName, String gemName, String annotationName, String annotationFqn,
List<GemValueInfo> gemValueInfos, Element... originatingElements) {
this.gemPackageName = gemPackageName;
this.gemName = annotationName + "Gem";
this.gemName = gemName;
this.annotationName = annotationName;
this.annotationFqn = annotationFqn;
this.gemValueInfos = gemValueInfos;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl

// create gem info
DeclaredType gemDeclaredType = util.getAnnotationValue( gemDefinitionMirror, "value", DeclaredType.class );
String annotationName = util.getSimpleName( gemDeclaredType );
String gemName = getGemName( gemDefinitionMirror, annotationName );
PackageElement pkg = processingEnv.getElementUtils().getPackageOf( definingElement );
String gemName = util.getSimpleName( gemDeclaredType );
String gemFqn = util.getFullyQualifiedName( gemDeclaredType );
String gemPackage = pkg.getQualifiedName().toString();

Expand All @@ -108,6 +109,7 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl
GemInfo gemInfo = new GemInfo(
gemPackage,
gemName,
annotationName,
gemFqn,
gemValueInfos,
definingElement,
Expand All @@ -116,6 +118,14 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl
gemInfos.add( gemInfo );
}

private String getGemName(AnnotationMirror gemDefinitionMirror, String annotationName) {
String implementationName = util.getAnnotationValue( gemDefinitionMirror, "implementationName", String.class );
if ( implementationName != null ) {
return implementationName.replace( "<CLASS_NAME>", annotationName );
}
return annotationName + "Gem";
}

private void postProcessGemInfo() {
for ( GemInfo gemInfo : gemInfos ) {
for ( GemValueInfo gemValueInfo : gemInfo.getGemValueInfos() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ void example() throws IOException {
);
File generatedDir = compile( new GemProcessor(), src );
assertGeneratedFileContent( "BuilderGem", generatedDir );
assertGeneratedFileContent( "CustomBuilderGem", generatedDir );
assertGeneratedFileContent( "SomeAnnotationGem", generatedDir );
assertGeneratedFileContent( "SomeAnnotationsGem", generatedDir );
assertGeneratedFileContent( "SomeArrayAnnotationGem", generatedDir );
Expand Down Expand Up @@ -145,6 +146,7 @@ private String getSource() {
"@GemDefinition(value = SomeAnnotations.class)\n" +
"@GemDefinition(value = SomeArrayAnnotation.class)\n" +
"@GemDefinition(value = Builder.class)\n" +
"@GemDefinition(value = Builder.class, implementationName = \"Custom<CLASS_NAME>Gem\")\n" +
"public class GemGenerator {\n" +
"}";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.mapstruct.tools.gem.processor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.AbstractAnnotationValueVisitor8;
import javax.lang.model.util.ElementFilter;
import org.mapstruct.tools.gem.Gem;
import org.mapstruct.tools.gem.GemValue;


public class CustomBuilderGem implements Gem {

private final AnnotationMirror mirror;

private CustomBuilderGem( BuilderImpl builder ) {
mirror = builder.mirror;
}

@Override
public AnnotationMirror mirror( ) {
return mirror;
}

@Override
public boolean isValid( ) {
return true;
}

public static CustomBuilderGem instanceOn(Element element) {
return build( element, new BuilderImpl() );
}

public static CustomBuilderGem instanceOn(AnnotationMirror mirror ) {
return build( mirror, new BuilderImpl() );
}

public static <T> T build(Element element, Builder_<T> builder) {
AnnotationMirror mirror = element.getAnnotationMirrors().stream()
.filter( a -> "org.mapstruct.tools.gem.test.Builder".contentEquals( ( ( TypeElement )a.getAnnotationType().asElement() ).getQualifiedName() ) )
.findAny()
.orElse( null );
return build( mirror, builder );
}

public static <T> T build(AnnotationMirror mirror, Builder_<T> builder ) {

// return fast
if ( mirror == null || builder == null ) {
return null;
}
builder.setMirror( mirror );
return builder.build();
}

/**
* A builder that can be implemented by the user to define custom logic e.g. in the
* build method, prior to creating the annotation gem.
*/
public interface Builder_<T> {

/**
* Sets the annotation mirror
*
* @param mirror the mirror which this gem represents
*
* @return the {@link Builder_} for this gem, representing {@link CustomBuilderGem}
*/
Builder_<T> setMirror( AnnotationMirror mirror );

/**
* The build method can be overriden in a custom custom implementation, which allows
* the user to define his own custom validation on the annotation.
*
* @return the representation of the annotation
*/
T build();
}

private static class BuilderImpl implements Builder_<CustomBuilderGem> {

private AnnotationMirror mirror;

public Builder_<CustomBuilderGem> setMirror( AnnotationMirror mirror ) {
this.mirror = mirror;
return this;
}

public CustomBuilderGem build() {
return new CustomBuilderGem( this );
}
}

}