mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-26 00:00:05 +08:00
#32 Establishing processing chain for model creation and transformation
This commit is contained in:
parent
9a4e51801f
commit
a565bed0c7
@ -18,9 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap;
|
package org.mapstruct.ap;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.AbstractProcessor;
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.annotation.processing.Processor;
|
||||||
import javax.annotation.processing.RoundEnvironment;
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||||
import javax.annotation.processing.SupportedOptions;
|
import javax.annotation.processing.SupportedOptions;
|
||||||
@ -28,18 +30,45 @@ import javax.lang.model.SourceVersion;
|
|||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.util.ElementKindVisitor6;
|
||||||
|
|
||||||
import net.java.dev.hickory.prism.GeneratePrism;
|
import net.java.dev.hickory.prism.GeneratePrism;
|
||||||
import net.java.dev.hickory.prism.GeneratePrisms;
|
import net.java.dev.hickory.prism.GeneratePrisms;
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.Options;
|
import org.mapstruct.ap.model.Options;
|
||||||
import org.mapstruct.ap.model.ReportingPolicy;
|
import org.mapstruct.ap.model.ReportingPolicy;
|
||||||
|
import org.mapstruct.ap.processor.DefaultModelElementProcessorContext;
|
||||||
|
import org.mapstruct.ap.processor.MapperCreationProcessor;
|
||||||
|
import org.mapstruct.ap.processor.MapperRenderingProcessor;
|
||||||
|
import org.mapstruct.ap.processor.MethodRetrievalProcessor;
|
||||||
|
import org.mapstruct.ap.processor.ModelElementProcessor;
|
||||||
|
import org.mapstruct.ap.processor.ModelElementProcessor.ProcessorContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link Processor} which generates the implementations for mapper interfaces
|
||||||
|
* (interfaces annotated with {@code @Mapper}.
|
||||||
|
* </p>
|
||||||
|
* Implementation notes:
|
||||||
|
* </p>
|
||||||
|
* The generation happens by incrementally building up a model representation of
|
||||||
|
* each mapper to be generated (a {@link Mapper} object), which is then written
|
||||||
|
* into the resulting Java source file using the FreeMarker template engine.
|
||||||
|
* </p>
|
||||||
|
* The model instantiation and processing happens in several phases/passes by applying
|
||||||
|
* a sequence of {@link ModelElementProcessor}s.
|
||||||
|
* </p>
|
||||||
|
* For reading annotation attributes, prisms as generated with help of the <a
|
||||||
|
* href="https://java.net/projects/hickory">Hickory</a> tool are used. These
|
||||||
|
* prisms allow a comfortable access to annotations and their attributes without
|
||||||
|
* depending on their class objects.
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
@SupportedAnnotationTypes("org.mapstruct.Mapper")
|
@SupportedAnnotationTypes("org.mapstruct.Mapper")
|
||||||
@GeneratePrisms({
|
@GeneratePrisms({
|
||||||
@GeneratePrism(value = Mapper.class, publicAccess = true),
|
@GeneratePrism(value = org.mapstruct.Mapper.class, publicAccess = true),
|
||||||
@GeneratePrism(value = Mapping.class, publicAccess = true),
|
@GeneratePrism(value = Mapping.class, publicAccess = true),
|
||||||
@GeneratePrism(value = Mappings.class, publicAccess = true)
|
@GeneratePrism(value = Mappings.class, publicAccess = true)
|
||||||
})
|
})
|
||||||
@ -63,32 +92,6 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
options = createOptions();
|
options = createOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public SourceVersion getSupportedSourceVersion() {
|
|
||||||
return SourceVersion.latestSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean process(
|
|
||||||
final Set<? extends TypeElement> annotations,
|
|
||||||
final RoundEnvironment roundEnvironment) {
|
|
||||||
|
|
||||||
for ( TypeElement oneAnnotation : annotations ) {
|
|
||||||
|
|
||||||
//Indicates that the annotation's type isn't on the class path of the compiled
|
|
||||||
//project. Let the compiler deal with that and print an appropriate error.
|
|
||||||
if ( oneAnnotation.getKind() != ElementKind.ANNOTATION_TYPE ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( Element oneAnnotatedElement : roundEnvironment.getElementsAnnotatedWith( oneAnnotation ) ) {
|
|
||||||
oneAnnotatedElement.accept( new MapperGenerationVisitor( processingEnv, options ), null );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ANNOTATIONS_CLAIMED_EXCLUSIVELY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Options createOptions() {
|
private Options createOptions() {
|
||||||
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
|
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
|
||||||
|
|
||||||
@ -97,4 +100,65 @@ public class MappingProcessor extends AbstractProcessor {
|
|||||||
unmappedTargetPolicy != null ? ReportingPolicy.valueOf( unmappedTargetPolicy ) : null
|
unmappedTargetPolicy != null ? ReportingPolicy.valueOf( unmappedTargetPolicy ) : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
|
return SourceVersion.latestSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnvironment) {
|
||||||
|
ProcessorContext context = new DefaultModelElementProcessorContext( processingEnv, options );
|
||||||
|
|
||||||
|
for ( TypeElement annotation : annotations ) {
|
||||||
|
|
||||||
|
//Indicates that the annotation's type isn't on the class path of the compiled
|
||||||
|
//project. Let the compiler deal with that and print an appropriate error.
|
||||||
|
if ( annotation.getKind() != ElementKind.ANNOTATION_TYPE ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( Element mapperElement : roundEnvironment.getElementsAnnotatedWith( annotation ) ) {
|
||||||
|
TypeElement mapperTypeElement = asTypeElement( mapperElement );
|
||||||
|
processMapperTypeElement( context, mapperTypeElement );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ANNOTATIONS_CLAIMED_EXCLUSIVELY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMapperTypeElement(ProcessorContext context, TypeElement mapperTypeElement) {
|
||||||
|
Object mapper = mapperTypeElement;
|
||||||
|
for ( ModelElementProcessor<?, ?> processor : getProcessors() ) {
|
||||||
|
mapper = process( context, processor, mapperTypeElement, mapper );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <P, R> R process(ProcessorContext context, ModelElementProcessor<P, R> processor,
|
||||||
|
TypeElement mapperTypeElement, Object modelElement) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
P sourceElement = (P) modelElement;
|
||||||
|
return processor.process( context, mapperTypeElement, sourceElement );
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Retrieve via service loader
|
||||||
|
private Iterable<ModelElementProcessor<?, ?>> getProcessors() {
|
||||||
|
return Arrays.<ModelElementProcessor<?, ?>>asList(
|
||||||
|
new MethodRetrievalProcessor(),
|
||||||
|
new MapperCreationProcessor(),
|
||||||
|
new MapperRenderingProcessor()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeElement asTypeElement(Element element) {
|
||||||
|
return element.accept(
|
||||||
|
new ElementKindVisitor6<TypeElement, Void>() {
|
||||||
|
@Override
|
||||||
|
public TypeElement visitTypeAsInterface(TypeElement e, Void p) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}, null
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,12 @@ import java.util.Set;
|
|||||||
*
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class SimpleMappingMethod extends MappingMethod {
|
public class BeanMappingMethod extends MappingMethod {
|
||||||
|
|
||||||
private final List<PropertyMapping> propertyMappings;
|
private final List<PropertyMapping> propertyMappings;
|
||||||
|
|
||||||
public SimpleMappingMethod(String name, String parameterName, Type sourceType, Type targetType,
|
public BeanMappingMethod(String name, String parameterName, Type sourceType, Type targetType,
|
||||||
List<PropertyMapping> propertyMappings) {
|
List<PropertyMapping> propertyMappings) {
|
||||||
super( name, parameterName, sourceType, targetType );
|
super( name, parameterName, sourceType, targetType );
|
||||||
this.propertyMappings = propertyMappings;
|
this.propertyMappings = propertyMappings;
|
||||||
}
|
}
|
@ -33,10 +33,11 @@ public class Mapper extends AbstractModelElement {
|
|||||||
private final List<Type> usedMapperTypes;
|
private final List<Type> usedMapperTypes;
|
||||||
private final Options options;
|
private final Options options;
|
||||||
private final SortedSet<Type> importedTypes;
|
private final SortedSet<Type> importedTypes;
|
||||||
|
private final boolean isErroneous;
|
||||||
|
|
||||||
public Mapper(String packageName, String interfaceName,
|
public Mapper(String packageName, String interfaceName,
|
||||||
String implementationName, List<MappingMethod> mappingMethods, List<Type> usedMapperTypes,
|
String implementationName, List<MappingMethod> mappingMethods, List<Type> usedMapperTypes,
|
||||||
Options options) {
|
Options options, boolean isErroneous) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.interfaceName = interfaceName;
|
this.interfaceName = interfaceName;
|
||||||
this.implementationName = implementationName;
|
this.implementationName = implementationName;
|
||||||
@ -44,6 +45,7 @@ public class Mapper extends AbstractModelElement {
|
|||||||
this.usedMapperTypes = usedMapperTypes;
|
this.usedMapperTypes = usedMapperTypes;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.importedTypes = determineImportedTypes();
|
this.importedTypes = determineImportedTypes();
|
||||||
|
this.isErroneous = isErroneous;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SortedSet<Type> determineImportedTypes() {
|
private SortedSet<Type> determineImportedTypes() {
|
||||||
@ -122,4 +124,8 @@ public class Mapper extends AbstractModelElement {
|
|||||||
public SortedSet<Type> getImportedTypes() {
|
public SortedSet<Type> getImportedTypes() {
|
||||||
return importedTypes;
|
return importedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isErroneous() {
|
||||||
|
return isErroneous;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,10 @@ public class Type implements Comparable<Type> {
|
|||||||
this( null, name, null, false, false, false );
|
this( null, name, null, false, false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type(String packageName, String name) {
|
||||||
|
this( packageName, name, null, false, false, false );
|
||||||
|
}
|
||||||
|
|
||||||
public Type(String packageName, String name, Type elementType, boolean isEnumType, boolean isCollectionType,
|
public Type(String packageName, String name, Type elementType, boolean isEnumType, boolean isCollectionType,
|
||||||
boolean isIterableType) {
|
boolean isIterableType) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
|
import javax.annotation.processing.Filer;
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.Options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of the processor context.
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
|
public class DefaultModelElementProcessorContext implements ModelElementProcessor.ProcessorContext {
|
||||||
|
|
||||||
|
private ProcessingEnvironment processingEnvironment;
|
||||||
|
private Options options;
|
||||||
|
|
||||||
|
public DefaultModelElementProcessorContext(ProcessingEnvironment processingEnvironment, Options options) {
|
||||||
|
this.processingEnvironment = processingEnvironment;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Filer getFiler() {
|
||||||
|
return processingEnvironment.getFiler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Types getTypeUtils() {
|
||||||
|
return processingEnvironment.getTypeUtils();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Elements getElementUtils() {
|
||||||
|
return processingEnvironment.getElementUtils();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Messager getMessager() {
|
||||||
|
return processingEnvironment.getMessager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Options getOptions() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
}
|
@ -16,10 +16,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap;
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
import java.beans.Introspector;
|
import java.beans.Introspector;
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -28,23 +27,20 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.Messager;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.AnnotationValue;
|
import javax.lang.model.element.AnnotationValue;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementVisitor;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.DeclaredType;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.ElementKindVisitor6;
|
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
import javax.tools.JavaFileObject;
|
|
||||||
|
|
||||||
|
import org.mapstruct.ap.MapperPrism;
|
||||||
import org.mapstruct.ap.conversion.Conversion;
|
import org.mapstruct.ap.conversion.Conversion;
|
||||||
import org.mapstruct.ap.conversion.Conversions;
|
import org.mapstruct.ap.conversion.Conversions;
|
||||||
|
import org.mapstruct.ap.model.BeanMappingMethod;
|
||||||
import org.mapstruct.ap.model.IterableMappingMethod;
|
import org.mapstruct.ap.model.IterableMappingMethod;
|
||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.MappingMethod;
|
import org.mapstruct.ap.model.MappingMethod;
|
||||||
@ -52,111 +48,63 @@ import org.mapstruct.ap.model.MappingMethodReference;
|
|||||||
import org.mapstruct.ap.model.Options;
|
import org.mapstruct.ap.model.Options;
|
||||||
import org.mapstruct.ap.model.PropertyMapping;
|
import org.mapstruct.ap.model.PropertyMapping;
|
||||||
import org.mapstruct.ap.model.ReportingPolicy;
|
import org.mapstruct.ap.model.ReportingPolicy;
|
||||||
import org.mapstruct.ap.model.SimpleMappingMethod;
|
|
||||||
import org.mapstruct.ap.model.Type;
|
import org.mapstruct.ap.model.Type;
|
||||||
import org.mapstruct.ap.model.source.Mapping;
|
import org.mapstruct.ap.model.source.Mapping;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
import org.mapstruct.ap.model.source.Parameter;
|
|
||||||
import org.mapstruct.ap.util.Executables;
|
import org.mapstruct.ap.util.Executables;
|
||||||
import org.mapstruct.ap.util.Filters;
|
import org.mapstruct.ap.util.Filters;
|
||||||
import org.mapstruct.ap.util.Strings;
|
import org.mapstruct.ap.util.Strings;
|
||||||
import org.mapstruct.ap.util.TypeUtil;
|
import org.mapstruct.ap.util.TypeUtil;
|
||||||
import org.mapstruct.ap.writer.ModelWriter;
|
|
||||||
|
|
||||||
import static javax.lang.model.util.ElementFilter.methodsIn;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link ElementVisitor} which generates the implementations for mapper
|
* A {@link ModelElementProcessor} which creates a {@link Mapper} from the given
|
||||||
* interfaces (interfaces annotated with {@code @Mapper}.
|
* list of {@link Method}s.
|
||||||
* </p>
|
|
||||||
* Implementation notes:
|
|
||||||
* </p>
|
|
||||||
* The mapper generation happens by building up a model representation of
|
|
||||||
* the mapper to be generated (a {@link Mapper} object), which is then written
|
|
||||||
* into a file using the FreeMarker template engine.
|
|
||||||
* </p>
|
|
||||||
* The model instantiation happens in two phases/passes: The first one retrieves
|
|
||||||
* the mapping methods of the given interfaces and their configuration (the
|
|
||||||
* <i>source</i> model). In the second pass the individual methods are
|
|
||||||
* aggregated into the <i>target</i> model, which contains a {@link BeanMapping}
|
|
||||||
* each pair of source and target type which has references to forward and
|
|
||||||
* reverse mapping methods as well as the methods for mapping the element types
|
|
||||||
* (if it is a collection mapping) and {@link Conversion}s if applicable.
|
|
||||||
* </p>
|
|
||||||
* For reading annotation attributes, prisms as generated with help of the <a
|
|
||||||
* href="https://java.net/projects/hickory">Hickory</a> tool are used. These
|
|
||||||
* prisms allow a comfortable access to annotations and their attributes without
|
|
||||||
* depending on their class objects.
|
|
||||||
*
|
*
|
||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
public class MapperCreationProcessor implements ModelElementProcessor<List<Method>, Mapper> {
|
||||||
|
|
||||||
private static final String IMPLEMENTATION_SUFFIX = "Impl";
|
private static final String IMPLEMENTATION_SUFFIX = "Impl";
|
||||||
|
|
||||||
private final ProcessingEnvironment processingEnvironment;
|
private Elements elementUtils;
|
||||||
private final Types typeUtils;
|
private Types typeUtils;
|
||||||
private final Elements elementUtils;
|
private Messager messager;
|
||||||
private final TypeUtil typeUtil;
|
private Options options;
|
||||||
private final Conversions conversions;
|
|
||||||
private final Options options;
|
|
||||||
|
|
||||||
private boolean mappingErroneous = false;
|
private TypeUtil typeUtil;
|
||||||
|
private Conversions conversions;
|
||||||
|
private Executables executables;
|
||||||
|
|
||||||
public MapperGenerationVisitor(ProcessingEnvironment processingEnvironment, Options options) {
|
private boolean isErroneous = false;
|
||||||
this.processingEnvironment = processingEnvironment;
|
|
||||||
this.typeUtils = processingEnvironment.getTypeUtils();
|
|
||||||
this.elementUtils = processingEnvironment.getElementUtils();
|
|
||||||
this.typeUtil = new TypeUtil( elementUtils, typeUtils );
|
|
||||||
this.conversions = new Conversions( elementUtils, typeUtils, typeUtil );
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitTypeAsInterface(TypeElement element, Void p) {
|
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<Method> sourceElement) {
|
||||||
Mapper model = retrieveModel( element );
|
this.elementUtils = context.getElementUtils();
|
||||||
|
this.typeUtils = context.getTypeUtils();
|
||||||
|
this.messager = context.getMessager();
|
||||||
|
this.options = context.getOptions();
|
||||||
|
|
||||||
if ( !mappingErroneous ) {
|
this.typeUtil = new TypeUtil( context.getElementUtils(), context.getTypeUtils() );
|
||||||
String sourceFileName = element.getQualifiedName() + IMPLEMENTATION_SUFFIX;
|
this.conversions = new Conversions( elementUtils, typeUtils, typeUtil );
|
||||||
writeModelToSourceFile( sourceFileName, model );
|
this.executables = new Executables( typeUtil );
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return getMapper( mapperTypeElement, sourceElement );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeModelToSourceFile(String fileName, Mapper model) {
|
public Mapper getMapper(TypeElement element, List<Method> methods) {
|
||||||
JavaFileObject sourceFile;
|
|
||||||
try {
|
|
||||||
sourceFile = processingEnvironment.getFiler().createSourceFile( fileName );
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
throw new RuntimeException( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
new ModelWriter().writeModel( sourceFile, model );
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mapper retrieveModel(TypeElement element) {
|
|
||||||
//1.) build up "source" model
|
|
||||||
List<Method> methods = retrieveMethods( element, true );
|
|
||||||
|
|
||||||
//2.) build up aggregated "target" model
|
|
||||||
List<MappingMethod> mappings = getMappingMethods(
|
|
||||||
methods,
|
|
||||||
getEffectiveUnmappedTargetPolicy( element )
|
|
||||||
);
|
|
||||||
List<Type> usedMapperTypes = getUsedMapperTypes( element );
|
List<Type> usedMapperTypes = getUsedMapperTypes( element );
|
||||||
|
|
||||||
Mapper mapper = new Mapper(
|
ReportingPolicy unmappedTargetPolicy = getEffectiveUnmappedTargetPolicy( element );
|
||||||
|
|
||||||
|
return new Mapper(
|
||||||
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
|
elementUtils.getPackageOf( element ).getQualifiedName().toString(),
|
||||||
element.getSimpleName().toString(),
|
element.getSimpleName().toString(),
|
||||||
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
element.getSimpleName() + IMPLEMENTATION_SUFFIX,
|
||||||
mappings,
|
getMappingMethods( methods, unmappedTargetPolicy ),
|
||||||
usedMapperTypes,
|
usedMapperTypes,
|
||||||
options
|
options,
|
||||||
|
isErroneous
|
||||||
);
|
);
|
||||||
|
|
||||||
return mapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,6 +132,15 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Type> getUsedMapperTypes(TypeElement element) {
|
||||||
|
List<Type> usedMapperTypes = new LinkedList<Type>();
|
||||||
|
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
||||||
|
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
||||||
|
usedMapperTypes.add( typeUtil.retrieveType( usedMapper ) );
|
||||||
|
}
|
||||||
|
return usedMapperTypes;
|
||||||
|
}
|
||||||
|
|
||||||
private List<MappingMethod> getMappingMethods(List<Method> methods, ReportingPolicy unmappedTargetPolicy) {
|
private List<MappingMethod> getMappingMethods(List<Method> methods, ReportingPolicy unmappedTargetPolicy) {
|
||||||
List<MappingMethod> mappingMethods = new ArrayList<MappingMethod>();
|
List<MappingMethod> mappingMethods = new ArrayList<MappingMethod>();
|
||||||
|
|
||||||
@ -203,7 +160,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
mappingMethods.add( getIterableMappingMethod( methods, method ) );
|
mappingMethods.add( getIterableMappingMethod( methods, method ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mappingMethods.add( getSimpleMappingMethod( methods, method, unmappedTargetPolicy ) );
|
mappingMethods.add( getBeanMappingMethod( methods, method, unmappedTargetPolicy ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mappingMethods;
|
return mappingMethods;
|
||||||
@ -218,8 +175,8 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
return reversed;
|
return reversed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingMethod getSimpleMappingMethod(List<Method> methods, Method method,
|
private MappingMethod getBeanMappingMethod(List<Method> methods, Method method,
|
||||||
ReportingPolicy unmappedTargetPolicy) {
|
ReportingPolicy unmappedTargetPolicy) {
|
||||||
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
|
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
|
||||||
Set<String> mappedTargetProperties = new HashSet<String>();
|
Set<String> mappedTargetProperties = new HashSet<String>();
|
||||||
|
|
||||||
@ -240,21 +197,21 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
elementUtils.getAllMembers( returnTypeElement )
|
elementUtils.getAllMembers( returnTypeElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<String> sourceProperties = Executables.getPropertyNames(
|
Set<String> sourceProperties = executables.getPropertyNames(
|
||||||
Filters.getterMethodsIn( sourceGetters )
|
Filters.getterMethodsIn( sourceGetters )
|
||||||
);
|
);
|
||||||
Set<String> targetProperties = Executables.getPropertyNames(
|
Set<String> targetProperties = executables.getPropertyNames(
|
||||||
Filters.setterMethodsIn( targetSetters )
|
Filters.setterMethodsIn( targetSetters )
|
||||||
);
|
);
|
||||||
|
|
||||||
reportErrorIfMappedPropertiesDontExist( method, sourceProperties, targetProperties );
|
reportErrorIfMappedPropertiesDontExist( method, sourceProperties, targetProperties );
|
||||||
|
|
||||||
for ( ExecutableElement getterMethod : sourceGetters ) {
|
for ( ExecutableElement getterMethod : sourceGetters ) {
|
||||||
String sourcePropertyName = Executables.getPropertyName( getterMethod );
|
String sourcePropertyName = executables.getPropertyName( getterMethod );
|
||||||
Mapping mapping = mappings.get( sourcePropertyName );
|
Mapping mapping = mappings.get( sourcePropertyName );
|
||||||
|
|
||||||
for ( ExecutableElement setterMethod : targetSetters ) {
|
for ( ExecutableElement setterMethod : targetSetters ) {
|
||||||
String targetPropertyName = Executables.getPropertyName( setterMethod );
|
String targetPropertyName = executables.getPropertyName( setterMethod );
|
||||||
|
|
||||||
if ( targetPropertyName.equals( mapping != null ? mapping.getTargetName() : sourcePropertyName ) ) {
|
if ( targetPropertyName.equals( mapping != null ? mapping.getTargetName() : sourcePropertyName ) ) {
|
||||||
PropertyMapping property = getPropertyMapping(
|
PropertyMapping property = getPropertyMapping(
|
||||||
@ -278,7 +235,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
mappedTargetProperties
|
mappedTargetProperties
|
||||||
);
|
);
|
||||||
|
|
||||||
return new SimpleMappingMethod(
|
return new BeanMappingMethod(
|
||||||
method.getName(),
|
method.getName(),
|
||||||
method.getParameterName(),
|
method.getParameterName(),
|
||||||
method.getSourceType(),
|
method.getSourceType(),
|
||||||
@ -287,10 +244,65 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reportErrorForUnmappedTargetPropertiesIfRequired(Method method,
|
||||||
|
ReportingPolicy unmappedTargetPolicy,
|
||||||
|
Set<String> targetProperties,
|
||||||
|
Set<String> mappedTargetProperties) {
|
||||||
|
|
||||||
|
if ( targetProperties.size() > mappedTargetProperties.size() &&
|
||||||
|
unmappedTargetPolicy.requiresReport() ) {
|
||||||
|
targetProperties.removeAll( mappedTargetProperties );
|
||||||
|
printMessage(
|
||||||
|
unmappedTargetPolicy,
|
||||||
|
MessageFormat.format(
|
||||||
|
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
|
||||||
|
targetProperties.size(),
|
||||||
|
Strings.join( targetProperties, ", " )
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method getReverseMappingMethod(List<Method> rawMethods, Method method) {
|
||||||
|
for ( Method oneMethod : rawMethods ) {
|
||||||
|
if ( oneMethod.reverses( method ) ) {
|
||||||
|
return oneMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportErrorIfMappedPropertiesDontExist(Method method, Set<String> sourceProperties,
|
||||||
|
Set<String> targetProperties) {
|
||||||
|
for ( Mapping mappedProperty : method.getMappings().values() ) {
|
||||||
|
if ( !sourceProperties.contains( mappedProperty.getSourceName() ) ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Unknown property \"%s\" in parameter type %s.",
|
||||||
|
mappedProperty.getSourceName(),
|
||||||
|
method.getSourceType()
|
||||||
|
), method.getExecutable(), mappedProperty.getMirror(), mappedProperty.getSourceAnnotationValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( !targetProperties.contains( mappedProperty.getTargetName() ) ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Unknown property \"%s\" in return type %s.",
|
||||||
|
mappedProperty.getTargetName(),
|
||||||
|
method.getTargetType()
|
||||||
|
), method.getExecutable(), mappedProperty.getMirror(), mappedProperty.getTargetAnnotationValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PropertyMapping getPropertyMapping(List<Method> methods, Method method, ExecutableElement getterMethod,
|
private PropertyMapping getPropertyMapping(List<Method> methods, Method method, ExecutableElement getterMethod,
|
||||||
ExecutableElement setterMethod) {
|
ExecutableElement setterMethod) {
|
||||||
Type sourceType = retrieveReturnType( getterMethod );
|
Type sourceType = executables.retrieveReturnType( getterMethod );
|
||||||
Type targetType = retrieveParameter( setterMethod ).getType();
|
Type targetType = executables.retrieveParameter( setterMethod ).getType();
|
||||||
|
|
||||||
MappingMethodReference propertyMappingMethod = getMappingMethodReference( methods, sourceType, targetType );
|
MappingMethodReference propertyMappingMethod = getMappingMethodReference( methods, sourceType, targetType );
|
||||||
Conversion conversion = conversions.getConversion(
|
Conversion conversion = conversions.getConversion(
|
||||||
@ -301,10 +313,10 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
PropertyMapping property = new PropertyMapping(
|
PropertyMapping property = new PropertyMapping(
|
||||||
method.getParameterName(),
|
method.getParameterName(),
|
||||||
Introspector.decapitalize( method.getTargetType().getName() ),
|
Introspector.decapitalize( method.getTargetType().getName() ),
|
||||||
Executables.getPropertyName( getterMethod ),
|
executables.getPropertyName( getterMethod ),
|
||||||
getterMethod.getSimpleName().toString(),
|
getterMethod.getSimpleName().toString(),
|
||||||
sourceType,
|
sourceType,
|
||||||
Executables.getPropertyName( setterMethod ),
|
executables.getPropertyName( setterMethod ),
|
||||||
setterMethod.getSimpleName().toString(),
|
setterMethod.getSimpleName().toString(),
|
||||||
targetType,
|
targetType,
|
||||||
propertyMappingMethod,
|
propertyMappingMethod,
|
||||||
@ -344,24 +356,35 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportErrorForUnmappedTargetPropertiesIfRequired(Method method,
|
private String getIterableConversionString(Conversions conversions, Type sourceElementType, Type targetElementType,
|
||||||
ReportingPolicy unmappedTargetPolicy,
|
boolean isToConversion) {
|
||||||
Set<String> targetProperties,
|
Conversion conversion = conversions.getConversion( sourceElementType, targetElementType );
|
||||||
Set<String> mappedTargetProperties) {
|
|
||||||
|
|
||||||
if ( targetProperties.size() > mappedTargetProperties.size() &&
|
if ( conversion == null ) {
|
||||||
unmappedTargetPolicy.requiresReport() ) {
|
return null;
|
||||||
targetProperties.removeAll( mappedTargetProperties );
|
|
||||||
printMessage(
|
|
||||||
unmappedTargetPolicy,
|
|
||||||
MessageFormat.format(
|
|
||||||
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
|
|
||||||
targetProperties.size(),
|
|
||||||
Strings.join( targetProperties, ", " )
|
|
||||||
),
|
|
||||||
method.getExecutable()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return conversion.to(
|
||||||
|
Introspector.decapitalize( sourceElementType.getName() ),
|
||||||
|
targetElementType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
||||||
|
Type returnType) {
|
||||||
|
for ( Method oneMethod : methods ) {
|
||||||
|
if ( oneMethod.getSourceType().equals( parameterType ) && oneMethod.getTargetType().equals( returnType ) ) {
|
||||||
|
return new MappingMethodReference(
|
||||||
|
oneMethod.getDeclaringMapper(),
|
||||||
|
oneMethod.getName(),
|
||||||
|
oneMethod.getParameterName(),
|
||||||
|
oneMethod.getSourceType(),
|
||||||
|
oneMethod.getTargetType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportErrorIfPropertyCanNotBeMapped(Method method, PropertyMapping property) {
|
private void reportErrorIfPropertyCanNotBeMapped(Method method, PropertyMapping property) {
|
||||||
@ -390,239 +413,16 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getIterableConversionString(Conversions conversions, Type sourceElementType, Type targetElementType,
|
|
||||||
boolean isToConversion) {
|
|
||||||
Conversion conversion = conversions.getConversion( sourceElementType, targetElementType );
|
|
||||||
|
|
||||||
if ( conversion == null ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return conversion.to(
|
|
||||||
Introspector.decapitalize( sourceElementType.getName() ),
|
|
||||||
targetElementType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Type> getUsedMapperTypes(TypeElement element) {
|
|
||||||
List<Type> usedMapperTypes = new LinkedList<Type>();
|
|
||||||
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
|
|
||||||
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
|
||||||
usedMapperTypes.add( typeUtil.retrieveType( usedMapper ) );
|
|
||||||
}
|
|
||||||
return usedMapperTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
|
||||||
Type returnType) {
|
|
||||||
for ( Method oneMethod : methods ) {
|
|
||||||
if ( oneMethod.getSourceType().equals( parameterType ) && oneMethod.getTargetType().equals( returnType ) ) {
|
|
||||||
return new MappingMethodReference(
|
|
||||||
oneMethod.getDeclaringMapper(),
|
|
||||||
oneMethod.getName(),
|
|
||||||
oneMethod.getParameterName(),
|
|
||||||
oneMethod.getSourceType(),
|
|
||||||
oneMethod.getTargetType()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method getReverseMappingMethod(List<Method> rawMethods, Method method) {
|
|
||||||
for ( Method oneMethod : rawMethods ) {
|
|
||||||
if ( oneMethod.reverses( method ) ) {
|
|
||||||
return oneMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the mapping methods declared by the given mapper type.
|
|
||||||
*
|
|
||||||
* @param element The type of interest
|
|
||||||
* @param implementationRequired Whether an implementation of this type must be generated or
|
|
||||||
* not. {@code true} if the type is the currently processed
|
|
||||||
* mapper interface, {@code false} if the given type is one
|
|
||||||
* referred to via {@code Mapper#uses()}.
|
|
||||||
*
|
|
||||||
* @return All mapping methods declared by the given type
|
|
||||||
*/
|
|
||||||
private List<Method> retrieveMethods(TypeElement element, boolean implementationRequired) {
|
|
||||||
List<Method> methods = new ArrayList<Method>();
|
|
||||||
|
|
||||||
MapperPrism mapperPrism = implementationRequired ? MapperPrism.getInstanceOn( element ) : null;
|
|
||||||
|
|
||||||
//TODO Extract to separate method
|
|
||||||
for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) {
|
|
||||||
Parameter parameter = retrieveParameter( method );
|
|
||||||
Type returnType = retrieveReturnType( method );
|
|
||||||
|
|
||||||
boolean mappingErroneous = false;
|
|
||||||
|
|
||||||
if ( implementationRequired ) {
|
|
||||||
if ( parameter.getType().isIterableType() && !returnType.isIterableType() ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
"Can't generate mapping method from iterable type to non-iterable type.",
|
|
||||||
method
|
|
||||||
);
|
|
||||||
mappingErroneous = true;
|
|
||||||
}
|
|
||||||
if ( !parameter.getType().isIterableType() && returnType.isIterableType() ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
"Can't generate mapping method from non-iterable type to iterable type.",
|
|
||||||
method
|
|
||||||
);
|
|
||||||
mappingErroneous = true;
|
|
||||||
}
|
|
||||||
if ( parameter.getType().isPrimitive() ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
"Can't generate mapping method with primitive parameter type.",
|
|
||||||
method
|
|
||||||
);
|
|
||||||
mappingErroneous = true;
|
|
||||||
}
|
|
||||||
if ( returnType.isPrimitive() ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
"Can't generate mapping method with primitive return type.",
|
|
||||||
method
|
|
||||||
);
|
|
||||||
mappingErroneous = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mappingErroneous ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//add method with property mappings if an implementation needs to be generated
|
|
||||||
if ( implementationRequired ) {
|
|
||||||
methods.add(
|
|
||||||
Method.forMethodRequiringImplementation(
|
|
||||||
method,
|
|
||||||
parameter.getName(),
|
|
||||||
parameter.getType(),
|
|
||||||
returnType,
|
|
||||||
getMappings( method )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//otherwise add reference to existing mapper method
|
|
||||||
else {
|
|
||||||
methods.add(
|
|
||||||
Method.forReferencedMethod(
|
|
||||||
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
|
|
||||||
method,
|
|
||||||
parameter.getName(),
|
|
||||||
parameter.getType(),
|
|
||||||
returnType
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add all methods of used mappers in order to reference them in the aggregated model
|
|
||||||
if ( implementationRequired ) {
|
|
||||||
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
|
||||||
methods.addAll(
|
|
||||||
retrieveMethods(
|
|
||||||
(TypeElement) ( (DeclaredType) usedMapper ).asElement(),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reportErrorIfMappedPropertiesDontExist(Method method, Set<String> sourceProperties,
|
|
||||||
Set<String> targetProperties) {
|
|
||||||
for ( Mapping mappedProperty : method.getMappings().values() ) {
|
|
||||||
if ( !sourceProperties.contains( mappedProperty.getSourceName() ) ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
String.format(
|
|
||||||
"Unknown property \"%s\" in parameter type %s.",
|
|
||||||
mappedProperty.getSourceName(),
|
|
||||||
method.getSourceType()
|
|
||||||
), method.getExecutable(), mappedProperty.getMirror(), mappedProperty.getSourceAnnotationValue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( !targetProperties.contains( mappedProperty.getTargetName() ) ) {
|
|
||||||
printMessage(
|
|
||||||
ReportingPolicy.ERROR,
|
|
||||||
String.format(
|
|
||||||
"Unknown property \"%s\" in return type %s.",
|
|
||||||
mappedProperty.getTargetName(),
|
|
||||||
method.getTargetType()
|
|
||||||
), method.getExecutable(), mappedProperty.getMirror(), mappedProperty.getTargetAnnotationValue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the mappings configured via {@code @Mapping} from the given
|
|
||||||
* method.
|
|
||||||
*
|
|
||||||
* @param method The method of interest
|
|
||||||
*
|
|
||||||
* @return The mappings for the given method, keyed by source property name
|
|
||||||
*/
|
|
||||||
private Map<String, Mapping> getMappings(ExecutableElement method) {
|
|
||||||
Map<String, Mapping> mappings = new HashMap<String, Mapping>();
|
|
||||||
|
|
||||||
MappingPrism mappingAnnotation = MappingPrism.getInstanceOn( method );
|
|
||||||
MappingsPrism mappingsAnnotation = MappingsPrism.getInstanceOn( method );
|
|
||||||
|
|
||||||
if ( mappingAnnotation != null ) {
|
|
||||||
mappings.put( mappingAnnotation.source(), Mapping.fromMappingPrism( mappingAnnotation ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mappingsAnnotation != null ) {
|
|
||||||
mappings.putAll( Mapping.fromMappingsPrism( mappingsAnnotation ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Parameter retrieveParameter(ExecutableElement method) {
|
|
||||||
List<? extends VariableElement> parameters = method.getParameters();
|
|
||||||
|
|
||||||
if ( parameters.size() != 1 ) {
|
|
||||||
//TODO: Log error
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
VariableElement parameter = parameters.get( 0 );
|
|
||||||
|
|
||||||
return new Parameter(
|
|
||||||
parameter.getSimpleName().toString(),
|
|
||||||
typeUtil.retrieveType( parameter.asType() )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Type retrieveReturnType(ExecutableElement method) {
|
|
||||||
return typeUtil.retrieveType( method.getReturnType() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element) {
|
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element) {
|
||||||
processingEnvironment.getMessager().printMessage( reportingPolicy.getDiagnosticKind(), message, element );
|
messager.printMessage( reportingPolicy.getDiagnosticKind(), message, element );
|
||||||
if ( reportingPolicy.failsBuild() ) {
|
if ( reportingPolicy.failsBuild() ) {
|
||||||
mappingErroneous = true;
|
isErroneous = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element,
|
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element,
|
||||||
AnnotationMirror annotationMirror, AnnotationValue annotationValue) {
|
AnnotationMirror annotationMirror, AnnotationValue annotationValue) {
|
||||||
processingEnvironment.getMessager()
|
messager
|
||||||
.printMessage(
|
.printMessage(
|
||||||
reportingPolicy.getDiagnosticKind(),
|
reportingPolicy.getDiagnosticKind(),
|
||||||
message,
|
message,
|
||||||
@ -631,7 +431,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
|
|||||||
annotationValue
|
annotationValue
|
||||||
);
|
);
|
||||||
if ( reportingPolicy.failsBuild() ) {
|
if ( reportingPolicy.failsBuild() ) {
|
||||||
mappingErroneous = true;
|
isErroneous = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.annotation.processing.Filer;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.Mapper;
|
||||||
|
import org.mapstruct.ap.writer.ModelWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ModelElementProcessor} which creates a Java source file representing
|
||||||
|
* the given {@link Mapper} object.
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
|
public class MapperRenderingProcessor implements ModelElementProcessor<Mapper, Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void process(ProcessorContext context, TypeElement mapperTypeElement, Mapper sourceElement) {
|
||||||
|
if ( !sourceElement.isErroneous() ) {
|
||||||
|
writeToSourceFile( context.getFiler(), sourceElement );
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToSourceFile(Filer filer, Mapper model) {
|
||||||
|
String fileName = model.getPackageName() + "." + model.getImplementationName();
|
||||||
|
|
||||||
|
JavaFileObject sourceFile;
|
||||||
|
try {
|
||||||
|
sourceFile = filer.createSourceFile( fileName );
|
||||||
|
}
|
||||||
|
catch ( IOException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
new ModelWriter().writeModel( sourceFile, model );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.MapperPrism;
|
||||||
|
import org.mapstruct.ap.MappingPrism;
|
||||||
|
import org.mapstruct.ap.MappingsPrism;
|
||||||
|
import org.mapstruct.ap.model.ReportingPolicy;
|
||||||
|
import org.mapstruct.ap.model.Type;
|
||||||
|
import org.mapstruct.ap.model.source.Mapping;
|
||||||
|
import org.mapstruct.ap.model.source.Method;
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
import org.mapstruct.ap.util.Executables;
|
||||||
|
import org.mapstruct.ap.util.TypeUtil;
|
||||||
|
|
||||||
|
import static javax.lang.model.util.ElementFilter.methodsIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ModelElementProcessor} which retrieves a list of {@link Method}s
|
||||||
|
* representing all the mapping methods of the given bean mapper type as well as
|
||||||
|
* all referenced mapper methods declared by other mappers referenced by the
|
||||||
|
* current mapper.
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
|
public class MethodRetrievalProcessor implements ModelElementProcessor<TypeElement, List<Method>> {
|
||||||
|
|
||||||
|
private Types typeUtils;
|
||||||
|
private Messager messager;
|
||||||
|
private TypeUtil typeUtil;
|
||||||
|
private Executables executables;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Method> process(ProcessorContext context, TypeElement mapperTypeElement, TypeElement sourceElement) {
|
||||||
|
this.typeUtils = context.getTypeUtils();
|
||||||
|
this.messager = context.getMessager();
|
||||||
|
this.typeUtil = new TypeUtil( context.getElementUtils(), typeUtils );
|
||||||
|
this.executables = new Executables( typeUtil );
|
||||||
|
|
||||||
|
return retrieveMethods( mapperTypeElement, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the mapping methods declared by the given mapper type.
|
||||||
|
*
|
||||||
|
* @param element The type of interest
|
||||||
|
* @param implementationRequired Whether an implementation of this type must be generated or
|
||||||
|
* not. {@code true} if the type is the currently processed
|
||||||
|
* mapper interface, {@code false} if the given type is one
|
||||||
|
* referred to via {@code Mapper#uses()}.
|
||||||
|
*
|
||||||
|
* @return All mapping methods declared by the given type
|
||||||
|
*/
|
||||||
|
private List<Method> retrieveMethods(TypeElement element, boolean implementationRequired) {
|
||||||
|
List<Method> methods = new ArrayList<Method>();
|
||||||
|
|
||||||
|
MapperPrism mapperPrism = implementationRequired ? MapperPrism.getInstanceOn( element ) : null;
|
||||||
|
|
||||||
|
//TODO Extract to separate method
|
||||||
|
for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) {
|
||||||
|
Parameter parameter = executables.retrieveParameter( method );
|
||||||
|
Type returnType = executables.retrieveReturnType( method );
|
||||||
|
|
||||||
|
boolean mappingErroneous = false;
|
||||||
|
|
||||||
|
if ( implementationRequired ) {
|
||||||
|
if ( parameter.getType().isIterableType() && !returnType.isIterableType() ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
"Can't generate mapping method from iterable type to non-iterable type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
mappingErroneous = true;
|
||||||
|
}
|
||||||
|
if ( !parameter.getType().isIterableType() && returnType.isIterableType() ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
"Can't generate mapping method from non-iterable type to iterable type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
mappingErroneous = true;
|
||||||
|
}
|
||||||
|
if ( parameter.getType().isPrimitive() ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
"Can't generate mapping method with primitive parameter type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
mappingErroneous = true;
|
||||||
|
}
|
||||||
|
if ( returnType.isPrimitive() ) {
|
||||||
|
printMessage(
|
||||||
|
ReportingPolicy.ERROR,
|
||||||
|
"Can't generate mapping method with primitive return type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
mappingErroneous = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mappingErroneous ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add method with property mappings if an implementation needs to be generated
|
||||||
|
if ( implementationRequired ) {
|
||||||
|
methods.add(
|
||||||
|
Method.forMethodRequiringImplementation(
|
||||||
|
method,
|
||||||
|
parameter.getName(),
|
||||||
|
parameter.getType(),
|
||||||
|
returnType,
|
||||||
|
getMappings( method )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//otherwise add reference to existing mapper method
|
||||||
|
else {
|
||||||
|
methods.add(
|
||||||
|
Method.forReferencedMethod(
|
||||||
|
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
|
||||||
|
method,
|
||||||
|
parameter.getName(),
|
||||||
|
parameter.getType(),
|
||||||
|
returnType
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add all methods of used mappers in order to reference them in the aggregated model
|
||||||
|
if ( implementationRequired ) {
|
||||||
|
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
||||||
|
methods.addAll(
|
||||||
|
retrieveMethods(
|
||||||
|
(TypeElement) ( (DeclaredType) usedMapper ).asElement(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the mappings configured via {@code @Mapping} from the given
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param method The method of interest
|
||||||
|
*
|
||||||
|
* @return The mappings for the given method, keyed by source property name
|
||||||
|
*/
|
||||||
|
private Map<String, Mapping> getMappings(ExecutableElement method) {
|
||||||
|
Map<String, Mapping> mappings = new HashMap<String, Mapping>();
|
||||||
|
|
||||||
|
MappingPrism mappingAnnotation = MappingPrism.getInstanceOn( method );
|
||||||
|
MappingsPrism mappingsAnnotation = MappingsPrism.getInstanceOn( method );
|
||||||
|
|
||||||
|
if ( mappingAnnotation != null ) {
|
||||||
|
mappings.put( mappingAnnotation.source(), Mapping.fromMappingPrism( mappingAnnotation ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mappingsAnnotation != null ) {
|
||||||
|
mappings.putAll( Mapping.fromMappingsPrism( mappingsAnnotation ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element) {
|
||||||
|
messager.printMessage( reportingPolicy.getDiagnosticKind(), message, element );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
|
import javax.annotation.processing.Filer;
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.Options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A processor which performs one task of the mapper generation, e.g. retrieving
|
||||||
|
* methods from the source {@link TypeElement}, performing validity checks or
|
||||||
|
* generating the output source file.
|
||||||
|
*
|
||||||
|
* @param <P> The parameter type processed by this processor
|
||||||
|
* @param <R> The return type created by this processor
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
|
public interface ModelElementProcessor<P, R> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context object passed to
|
||||||
|
* {@link ModelElementProcessor#process(ProcessorContext, TypeElement, Object)}
|
||||||
|
* providing access to common infrastructure objects such as {@link Types}
|
||||||
|
* etc.
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
*/
|
||||||
|
public interface ProcessorContext {
|
||||||
|
|
||||||
|
Filer getFiler();
|
||||||
|
|
||||||
|
Types getTypeUtils();
|
||||||
|
|
||||||
|
Elements getElementUtils();
|
||||||
|
|
||||||
|
Messager getMessager();
|
||||||
|
|
||||||
|
Options getOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the given source element, representing a Java bean mapper in
|
||||||
|
* one form or another.
|
||||||
|
*
|
||||||
|
* @param context Context providing common infrastructure objects.
|
||||||
|
* @param mapperTypeElement The original type element from which the given mapper object
|
||||||
|
* is derived.
|
||||||
|
* @param sourceElement The current representation of the bean mapper. Never
|
||||||
|
* {@code null} (the very first processor receives the original
|
||||||
|
* type element).
|
||||||
|
*
|
||||||
|
* @return The resulting representation of the bean mapper; may be the same
|
||||||
|
* as the source representation, e.g. if a given implementation just
|
||||||
|
* performs some sort of validity check. Implementations must never
|
||||||
|
* return {@code null} except for the very last processor which
|
||||||
|
* generates the resulting Java source file.
|
||||||
|
*/
|
||||||
|
R process(ProcessorContext context, TypeElement mapperTypeElement, P sourceElement);
|
||||||
|
}
|
@ -23,8 +23,12 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.Type;
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides functionality around {@link ExecutableElement}s.
|
* Provides functionality around {@link ExecutableElement}s.
|
||||||
*
|
*
|
||||||
@ -32,14 +36,17 @@ import javax.lang.model.type.TypeKind;
|
|||||||
*/
|
*/
|
||||||
public class Executables {
|
public class Executables {
|
||||||
|
|
||||||
private Executables() {
|
private final TypeUtil typeUtil;
|
||||||
|
|
||||||
|
public Executables(TypeUtil typeUtil) {
|
||||||
|
this.typeUtil = typeUtil;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isGetterMethod(ExecutableElement method) {
|
public boolean isGetterMethod(ExecutableElement method) {
|
||||||
return isNonBooleanGetterMethod( method ) || isBooleanGetterMethod( method );
|
return isNonBooleanGetterMethod( method ) || isBooleanGetterMethod( method );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNonBooleanGetterMethod(ExecutableElement method) {
|
private boolean isNonBooleanGetterMethod(ExecutableElement method) {
|
||||||
String name = method.getSimpleName().toString();
|
String name = method.getSimpleName().toString();
|
||||||
|
|
||||||
return method.getParameters().isEmpty() &&
|
return method.getParameters().isEmpty() &&
|
||||||
@ -48,7 +55,7 @@ public class Executables {
|
|||||||
method.getReturnType().getKind() != TypeKind.VOID;
|
method.getReturnType().getKind() != TypeKind.VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBooleanGetterMethod(ExecutableElement method) {
|
private boolean isBooleanGetterMethod(ExecutableElement method) {
|
||||||
String name = method.getSimpleName().toString();
|
String name = method.getSimpleName().toString();
|
||||||
|
|
||||||
return method.getParameters().isEmpty() &&
|
return method.getParameters().isEmpty() &&
|
||||||
@ -57,7 +64,7 @@ public class Executables {
|
|||||||
method.getReturnType().getKind() == TypeKind.BOOLEAN;
|
method.getReturnType().getKind() == TypeKind.BOOLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSetterMethod(ExecutableElement method) {
|
public boolean isSetterMethod(ExecutableElement method) {
|
||||||
String name = method.getSimpleName().toString();
|
String name = method.getSimpleName().toString();
|
||||||
|
|
||||||
if ( name.startsWith( "set" ) && name.length() > 3 && method.getParameters()
|
if ( name.startsWith( "set" ) && name.length() > 3 && method.getParameters()
|
||||||
@ -68,7 +75,7 @@ public class Executables {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getPropertyName(ExecutableElement getterOrSetterMethod) {
|
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
|
||||||
if ( isNonBooleanGetterMethod( getterOrSetterMethod ) ) {
|
if ( isNonBooleanGetterMethod( getterOrSetterMethod ) ) {
|
||||||
return Introspector.decapitalize(
|
return Introspector.decapitalize(
|
||||||
getterOrSetterMethod.getSimpleName().toString().substring( 3 )
|
getterOrSetterMethod.getSimpleName().toString().substring( 3 )
|
||||||
@ -88,13 +95,33 @@ public class Executables {
|
|||||||
throw new IllegalArgumentException( "Executable " + getterOrSetterMethod + " is not getter or setter method." );
|
throw new IllegalArgumentException( "Executable " + getterOrSetterMethod + " is not getter or setter method." );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getPropertyNames(List<ExecutableElement> propertyAccessors) {
|
public Set<String> getPropertyNames(List<ExecutableElement> propertyAccessors) {
|
||||||
Set<String> propertyNames = new HashSet<String>();
|
Set<String> propertyNames = new HashSet<String>();
|
||||||
|
|
||||||
for ( ExecutableElement executableElement : propertyAccessors ) {
|
for ( ExecutableElement executableElement : propertyAccessors ) {
|
||||||
propertyNames.add( Executables.getPropertyName( executableElement ) );
|
propertyNames.add( getPropertyName( executableElement ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return propertyNames;
|
return propertyNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Parameter retrieveParameter(ExecutableElement method) {
|
||||||
|
List<? extends VariableElement> parameters = method.getParameters();
|
||||||
|
|
||||||
|
if ( parameters.size() != 1 ) {
|
||||||
|
//TODO: Log error
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableElement parameter = parameters.get( 0 );
|
||||||
|
|
||||||
|
return new Parameter(
|
||||||
|
parameter.getSimpleName().toString(),
|
||||||
|
typeUtil.retrieveType( parameter.asType() )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type retrieveReturnType(ExecutableElement method) {
|
||||||
|
return typeUtil.retrieveType( method.getReturnType() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ import static javax.lang.model.util.ElementFilter.methodsIn;
|
|||||||
*/
|
*/
|
||||||
public class Filters {
|
public class Filters {
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
private static Executables executables = new Executables( null );
|
||||||
|
|
||||||
private Filters() {
|
private Filters() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +42,7 @@ public class Filters {
|
|||||||
List<ExecutableElement> getterMethods = new LinkedList<ExecutableElement>();
|
List<ExecutableElement> getterMethods = new LinkedList<ExecutableElement>();
|
||||||
|
|
||||||
for ( ExecutableElement method : methodsIn( elements ) ) {
|
for ( ExecutableElement method : methodsIn( elements ) ) {
|
||||||
if ( Executables.isGetterMethod( method ) ) {
|
if ( executables.isGetterMethod( method ) ) {
|
||||||
getterMethods.add( method );
|
getterMethods.add( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,7 +54,7 @@ public class Filters {
|
|||||||
List<ExecutableElement> setterMethods = new LinkedList<ExecutableElement>();
|
List<ExecutableElement> setterMethods = new LinkedList<ExecutableElement>();
|
||||||
|
|
||||||
for ( ExecutableElement method : methodsIn( elements ) ) {
|
for ( ExecutableElement method : methodsIn( elements ) ) {
|
||||||
if ( Executables.isSetterMethod( method ) ) {
|
if ( executables.isSetterMethod( method ) ) {
|
||||||
setterMethods.add( method );
|
setterMethods.add( method );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user