mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1566, #1253 Add support for initializing the AccessorNamingStrategy with Elements and Types and use Types for determining fluent setters
* This allows using generic builders
This commit is contained in:
parent
e69647f756
commit
6f19d56155
@ -114,7 +114,10 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
super.init( processingEnv );
|
super.init( processingEnv );
|
||||||
|
|
||||||
options = createOptions();
|
options = createOptions();
|
||||||
annotationProcessorContext = new AnnotationProcessorContext( processingEnv.getElementUtils() );
|
annotationProcessorContext = new AnnotationProcessorContext(
|
||||||
|
processingEnv.getElementUtils(),
|
||||||
|
processingEnv.getTypeUtils()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Options createOptions() {
|
private Options createOptions() {
|
||||||
|
@ -12,6 +12,7 @@ import java.util.ServiceLoader;
|
|||||||
|
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor;
|
||||||
@ -20,13 +21,14 @@ import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy;
|
|||||||
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
||||||
import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy;
|
import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.spi.ImmutablesBuilderProvider;
|
import org.mapstruct.ap.spi.ImmutablesBuilderProvider;
|
||||||
|
import org.mapstruct.ap.spi.MapStructProcessingEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps contextual data in the scope of the entire annotation processor ("application scope").
|
* Keeps contextual data in the scope of the entire annotation processor ("application scope").
|
||||||
*
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class AnnotationProcessorContext {
|
public class AnnotationProcessorContext implements MapStructProcessingEnvironment {
|
||||||
|
|
||||||
private List<AstModifyingAnnotationProcessor> astModifyingAnnotationProcessors;
|
private List<AstModifyingAnnotationProcessor> astModifyingAnnotationProcessors;
|
||||||
|
|
||||||
@ -36,11 +38,13 @@ public class AnnotationProcessorContext {
|
|||||||
|
|
||||||
private AccessorNamingUtils accessorNaming;
|
private AccessorNamingUtils accessorNaming;
|
||||||
private Elements elementUtils;
|
private Elements elementUtils;
|
||||||
|
private Types typeUtils;
|
||||||
|
|
||||||
public AnnotationProcessorContext(Elements elementUtils) {
|
public AnnotationProcessorContext(Elements elementUtils, Types typeUtils) {
|
||||||
astModifyingAnnotationProcessors = java.util.Collections.unmodifiableList(
|
astModifyingAnnotationProcessors = java.util.Collections.unmodifiableList(
|
||||||
findAstModifyingAnnotationProcessors() );
|
findAstModifyingAnnotationProcessors() );
|
||||||
this.elementUtils = elementUtils;
|
this.elementUtils = elementUtils;
|
||||||
|
this.typeUtils = typeUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,6 +71,7 @@ public class AnnotationProcessorContext {
|
|||||||
defaultBuilderProvider = new ImmutablesBuilderProvider();
|
defaultBuilderProvider = new ImmutablesBuilderProvider();
|
||||||
}
|
}
|
||||||
this.accessorNamingStrategy = Services.get( AccessorNamingStrategy.class, defaultAccessorNamingStrategy );
|
this.accessorNamingStrategy = Services.get( AccessorNamingStrategy.class, defaultAccessorNamingStrategy );
|
||||||
|
this.accessorNamingStrategy.init( this );
|
||||||
this.builderProvider = Services.get( BuilderProvider.class, defaultBuilderProvider );
|
this.builderProvider = Services.get( BuilderProvider.class, defaultBuilderProvider );
|
||||||
this.accessorNaming = new AccessorNamingUtils( this.accessorNamingStrategy );
|
this.accessorNaming = new AccessorNamingUtils( this.accessorNamingStrategy );
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
@ -86,6 +91,16 @@ public class AnnotationProcessorContext {
|
|||||||
return processors;
|
return processors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Elements getElementUtils() {
|
||||||
|
return elementUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Types getTypeUtils() {
|
||||||
|
return typeUtils;
|
||||||
|
}
|
||||||
|
|
||||||
public List<AstModifyingAnnotationProcessor> getAstModifyingAnnotationProcessors() {
|
public List<AstModifyingAnnotationProcessor> getAstModifyingAnnotationProcessors() {
|
||||||
return astModifyingAnnotationProcessors;
|
return astModifyingAnnotationProcessors;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,15 @@ import javax.lang.model.element.ExecutableElement;
|
|||||||
*/
|
*/
|
||||||
public interface AccessorNamingStrategy {
|
public interface AccessorNamingStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the accessor naming strategy with the MapStruct processing environment.
|
||||||
|
*
|
||||||
|
* @param processingEnvironment environment for facilities
|
||||||
|
*/
|
||||||
|
default void init(MapStructProcessingEnvironment processingEnvironment) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the given method.
|
* Returns the type of the given method.
|
||||||
*
|
*
|
||||||
|
@ -12,8 +12,10 @@ import javax.lang.model.element.TypeElement;
|
|||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.SimpleElementVisitor6;
|
import javax.lang.model.util.SimpleElementVisitor6;
|
||||||
import javax.lang.model.util.SimpleTypeVisitor6;
|
import javax.lang.model.util.SimpleTypeVisitor6;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
import org.mapstruct.ap.spi.util.IntrospectorUtils;
|
import org.mapstruct.ap.spi.util.IntrospectorUtils;
|
||||||
|
|
||||||
@ -26,6 +28,15 @@ public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
|
|||||||
|
|
||||||
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
||||||
|
|
||||||
|
protected Elements elementUtils;
|
||||||
|
protected Types typeUtils;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(MapStructProcessingEnvironment processingEnvironment) {
|
||||||
|
this.elementUtils = processingEnvironment.getElementUtils();
|
||||||
|
this.typeUtils = processingEnvironment.getTypeUtils();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodType getMethodType(ExecutableElement method) {
|
public MethodType getMethodType(ExecutableElement method) {
|
||||||
if ( isGetterMethod( method ) ) {
|
if ( isGetterMethod( method ) ) {
|
||||||
@ -90,8 +101,7 @@ public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
|
|||||||
return method.getParameters().size() == 1 &&
|
return method.getParameters().size() == 1 &&
|
||||||
!JAVA_JAVAX_PACKAGE.matcher( method.getEnclosingElement().asType().toString() ).matches() &&
|
!JAVA_JAVAX_PACKAGE.matcher( method.getEnclosingElement().asType().toString() ).matches() &&
|
||||||
!isAdderWithUpperCase4thCharacter( method ) &&
|
!isAdderWithUpperCase4thCharacter( method ) &&
|
||||||
//TODO The Types need to be compared with Types#isSameType(TypeMirror, TypeMirror)
|
typeUtils.isAssignable( method.getReturnType(), method.getEnclosingElement().asType() );
|
||||||
method.getReturnType().toString().equals( method.getEnclosingElement().asType().toString() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.spi;
|
||||||
|
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapStruct will provide the implementations of its SPIs with on object implementing this interface so they can use
|
||||||
|
* facilities provided by it. It is a subset of {@link javax.annotation.processing.ProcessingEnvironment
|
||||||
|
* ProcessingEnvironment}.
|
||||||
|
*
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
* @see javax.annotation.processing.ProcessingEnvironment
|
||||||
|
*/
|
||||||
|
public interface MapStructProcessingEnvironment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an implementation of some utility methods for
|
||||||
|
* operating on elements
|
||||||
|
*
|
||||||
|
* @return element utilities
|
||||||
|
*/
|
||||||
|
Elements getElementUtils();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an implementation of some utility methods for
|
||||||
|
* operating on types.
|
||||||
|
*
|
||||||
|
* @return type utilities
|
||||||
|
*/
|
||||||
|
Types getTypeUtils();
|
||||||
|
|
||||||
|
}
|
@ -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.bugs._1566;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
|
||||||
|
String id;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T id(final String id) {
|
||||||
|
this.id = id;
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
}
|
@ -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.bugs._1566;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface Issue1566Mapper {
|
||||||
|
|
||||||
|
Issue1566Mapper INSTANCE = Mappers.getMapper( Issue1566Mapper.class );
|
||||||
|
|
||||||
|
Target map(Source source);
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._1566;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
@WithClasses({
|
||||||
|
AbstractBuilder.class,
|
||||||
|
Issue1566Mapper.class,
|
||||||
|
Source.class,
|
||||||
|
Target.class
|
||||||
|
})
|
||||||
|
@IssueKey("1566")
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
public class Issue1566Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void genericMapperIsCorrectlyUsed() {
|
||||||
|
Source source = new Source();
|
||||||
|
source.setId( "id-123" );
|
||||||
|
source.setName( "Source" );
|
||||||
|
|
||||||
|
Target target = Issue1566Mapper.INSTANCE.map( source );
|
||||||
|
|
||||||
|
assertThat( target ).isNotNull();
|
||||||
|
assertThat( target.getId() ).isEqualTo( "id-123" );
|
||||||
|
assertThat( target.getName() ).isEqualTo( "Source" );
|
||||||
|
}
|
||||||
|
}
|
@ -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.bugs._1566;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Source {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._1566;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Filip Hrisafov
|
||||||
|
*/
|
||||||
|
public class Target {
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private Target(String id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AbstractBuilder<Builder> {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Builder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Target build() {
|
||||||
|
return new Target( id, name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user