mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#120 Propagate built-in methods as MappingMethod implementation to the Mapper in order to avoid the need for specific handling in the template
This commit is contained in:
parent
34484c6686
commit
47ecc23fa0
@ -18,27 +18,35 @@
|
||||
*/
|
||||
package org.mapstruct.ap.builtin;
|
||||
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
import java.util.HashSet;
|
||||
import org.mapstruct.ap.model.common.TypeFactory;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.ap.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
|
||||
/**
|
||||
* Registry for all build in methods.
|
||||
* Registry for all built-in methods.
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class BuiltInMappingMethods extends HashSet<BuiltInMethod> {
|
||||
public class BuiltInMappingMethods {
|
||||
|
||||
public BuiltInMappingMethods( TypeFactory typeFactory ) {
|
||||
private final List<BuiltInMethod> builtInMethods;
|
||||
|
||||
add( new JaxbElemToValue( typeFactory ) );
|
||||
add( new ListOfJaxbElemToListOfValue( typeFactory ) );
|
||||
add( new DateToXmlGregorianCalendar( typeFactory ) );
|
||||
add( new XmlGregorianCalendarToDate( typeFactory ) );
|
||||
add( new StringToXmlGregorianCalendar( typeFactory ) );
|
||||
add( new XmlGregorianCalendarToString( typeFactory ) );
|
||||
add( new CalendarToXmlGregorianCalendar( typeFactory ) );
|
||||
add( new XmlGregorianCalendarToCalendar( typeFactory ) );
|
||||
public BuiltInMappingMethods(TypeFactory typeFactory) {
|
||||
builtInMethods = Arrays.asList(
|
||||
new JaxbElemToValue( typeFactory ),
|
||||
new ListOfJaxbElemToListOfValue( typeFactory ),
|
||||
new DateToXmlGregorianCalendar( typeFactory ),
|
||||
new XmlGregorianCalendarToDate( typeFactory ),
|
||||
new StringToXmlGregorianCalendar( typeFactory ),
|
||||
new XmlGregorianCalendarToString( typeFactory ),
|
||||
new CalendarToXmlGregorianCalendar( typeFactory ),
|
||||
new XmlGregorianCalendarToCalendar( typeFactory )
|
||||
);
|
||||
}
|
||||
|
||||
public List<BuiltInMethod> getBuiltInMethods() {
|
||||
return builtInMethods;
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,9 @@
|
||||
*/
|
||||
package org.mapstruct.ap.model;
|
||||
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@ -54,14 +52,13 @@ public class Mapper extends ModelElement {
|
||||
private final List<Annotation> annotations;
|
||||
private final List<MappingMethod> mappingMethods;
|
||||
private final List<MapperReference> referencedMappers;
|
||||
private final Set<BuiltInMethod> builtInMethods;
|
||||
private final boolean suppressGeneratorTimestamp;
|
||||
private final Accessibility accessibility;
|
||||
|
||||
private Mapper(TypeFactory typeFactory, String packageName, boolean superTypeIsInterface, String interfaceName,
|
||||
String implementationName, List<MappingMethod> mappingMethods,
|
||||
List<MapperReference> referencedMappers, boolean suppressGeneratorTimestamp,
|
||||
Set<BuiltInMethod> builtInMethods, Accessibility accessibility) {
|
||||
Accessibility accessibility) {
|
||||
this.packageName = packageName;
|
||||
this.superTypeIsInterface = superTypeIsInterface;
|
||||
this.interfaceName = interfaceName;
|
||||
@ -69,7 +66,6 @@ public class Mapper extends ModelElement {
|
||||
this.annotations = new ArrayList<Annotation>();
|
||||
this.mappingMethods = mappingMethods;
|
||||
this.referencedMappers = referencedMappers;
|
||||
this.builtInMethods = builtInMethods;
|
||||
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
|
||||
this.typeFactory = typeFactory;
|
||||
this.accessibility = accessibility;
|
||||
@ -81,7 +77,6 @@ public class Mapper extends ModelElement {
|
||||
private TypeElement element;
|
||||
private List<MappingMethod> mappingMethods;
|
||||
private List<MapperReference> mapperReferences;
|
||||
private Set<BuiltInMethod> builtInMethods;
|
||||
|
||||
private Elements elementUtils;
|
||||
private boolean suppressGeneratorTimestamp;
|
||||
@ -101,11 +96,6 @@ public class Mapper extends ModelElement {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder builtInMethods(Set<BuiltInMethod> builtInMethods) {
|
||||
this.builtInMethods = builtInMethods;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder suppressGeneratorTimestamp(boolean suppressGeneratorTimestamp) {
|
||||
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
|
||||
return this;
|
||||
@ -131,7 +121,6 @@ public class Mapper extends ModelElement {
|
||||
mappingMethods,
|
||||
mapperReferences,
|
||||
suppressGeneratorTimestamp,
|
||||
builtInMethods,
|
||||
Accessibility.fromModifiers( element.getModifiers() )
|
||||
);
|
||||
}
|
||||
@ -158,12 +147,6 @@ public class Mapper extends ModelElement {
|
||||
addWithDependents( importedTypes, annotation.getType() );
|
||||
}
|
||||
|
||||
for ( BuiltInMethod builtInMethod : builtInMethods ) {
|
||||
for ( Type type : builtInMethod.getImportTypes() ) {
|
||||
addWithDependents( importedTypes, type );
|
||||
}
|
||||
}
|
||||
|
||||
return importedTypes;
|
||||
}
|
||||
|
||||
@ -250,8 +233,4 @@ public class Mapper extends ModelElement {
|
||||
public Accessibility getAccessibility() {
|
||||
return accessibility;
|
||||
}
|
||||
|
||||
public Set<BuiltInMethod> getBuiltInMethods() {
|
||||
return builtInMethods;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright 2012-2014 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.model;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.model.common.Type;
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
|
||||
/**
|
||||
* A mapping method which is not based on an actual method declared in the original mapper interface but is added as
|
||||
* private method to map a certain source/target type combination. Based on a {@link BuiltInMethod}.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public class VirtualMappingMethod extends MappingMethod {
|
||||
|
||||
private final String templateName;
|
||||
private final Set<Type> importTypes;
|
||||
|
||||
public VirtualMappingMethod(BuiltInMethod method) {
|
||||
super( method );
|
||||
this.importTypes = method.getImportTypes();
|
||||
this.templateName = method.getClass().getName() + ".ftl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Type> getImportTypes() {
|
||||
return importTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ( ( templateName == null ) ? 0 : templateName.hashCode() );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if ( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
VirtualMappingMethod other = (VirtualMappingMethod) obj;
|
||||
if ( templateName == null ) {
|
||||
if ( other.templateName != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( !templateName.equals( other.templateName ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -22,18 +22,16 @@ import java.io.Writer;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.writer.FreeMarkerModelElementWriter;
|
||||
import org.mapstruct.ap.writer.FreeMarkerWritable;
|
||||
import org.mapstruct.ap.writer.Writable;
|
||||
|
||||
/**
|
||||
* Base class of all model elements.
|
||||
* <p>
|
||||
* Implements the {@link Writable} contract to write model elements into source code files using FreeMarker templates.
|
||||
* By default, the fully-qualified class name of the given model element type, appended with the extension {@code *.ftl}
|
||||
* is used as template file name.
|
||||
* Base class of all model elements. Implements the {@link Writable} contract to write model elements into source code
|
||||
* files.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public abstract class ModelElement implements Writable {
|
||||
public abstract class ModelElement extends FreeMarkerWritable {
|
||||
|
||||
@Override
|
||||
public void write(Context context, Writer writer) throws Exception {
|
||||
|
@ -36,13 +36,10 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import org.mapstruct.ap.model.common.ConversionContext;
|
||||
|
||||
import org.mapstruct.ap.builtin.BuiltInMappingMethods;
|
||||
import org.mapstruct.ap.conversion.ConversionProvider;
|
||||
import org.mapstruct.ap.conversion.Conversions;
|
||||
import org.mapstruct.ap.model.common.DefaultConversionContext;
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
import org.mapstruct.ap.builtin.BuiltInMappingMethods;
|
||||
import org.mapstruct.ap.model.BeanMappingMethod;
|
||||
import org.mapstruct.ap.model.DefaultMapperReference;
|
||||
import org.mapstruct.ap.model.IterableMappingMethod;
|
||||
@ -53,11 +50,15 @@ import org.mapstruct.ap.model.MappingMethod;
|
||||
import org.mapstruct.ap.model.MethodReference;
|
||||
import org.mapstruct.ap.model.PropertyMapping;
|
||||
import org.mapstruct.ap.model.TypeConversion;
|
||||
import org.mapstruct.ap.model.VirtualMappingMethod;
|
||||
import org.mapstruct.ap.model.common.ConversionContext;
|
||||
import org.mapstruct.ap.model.common.DefaultConversionContext;
|
||||
import org.mapstruct.ap.model.common.Parameter;
|
||||
import org.mapstruct.ap.model.common.Type;
|
||||
import org.mapstruct.ap.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.model.source.Method;
|
||||
import org.mapstruct.ap.model.source.BuiltInMethod;
|
||||
import org.mapstruct.ap.model.source.Mapping;
|
||||
import org.mapstruct.ap.model.source.Method;
|
||||
import org.mapstruct.ap.model.source.SourceMethod;
|
||||
import org.mapstruct.ap.option.Options;
|
||||
import org.mapstruct.ap.option.ReportingPolicy;
|
||||
@ -82,7 +83,12 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
private TypeFactory typeFactory;
|
||||
private Conversions conversions;
|
||||
private BuiltInMappingMethods builtInMethods;
|
||||
private Set<BuiltInMethod> usedBuiltInMethods;
|
||||
|
||||
/**
|
||||
* Private methods which are not present in the original mapper interface and are added to map certain property
|
||||
* types.
|
||||
*/
|
||||
private Set<VirtualMappingMethod> virtualMethods;
|
||||
|
||||
@Override
|
||||
public Mapper process(ProcessorContext context, TypeElement mapperTypeElement, List<SourceMethod> sourceModel) {
|
||||
@ -95,7 +101,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
this.conversions = new Conversions( elementUtils, typeFactory );
|
||||
|
||||
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
|
||||
this.usedBuiltInMethods = new HashSet<BuiltInMethod>();
|
||||
this.virtualMethods = new HashSet<VirtualMappingMethod>();
|
||||
|
||||
return getMapper( mapperTypeElement, sourceModel );
|
||||
}
|
||||
@ -109,6 +115,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
ReportingPolicy unmappedTargetPolicy = getEffectiveUnmappedTargetPolicy( element );
|
||||
List<MapperReference> mapperReferences = getReferencedMappers( element );
|
||||
List<MappingMethod> mappingMethods = getMappingMethods( mapperReferences, methods, unmappedTargetPolicy );
|
||||
mappingMethods.addAll( virtualMethods );
|
||||
|
||||
Mapper mapper = new Mapper.Builder()
|
||||
.element( element )
|
||||
@ -117,10 +124,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
.suppressGeneratorTimestamp( options.isSuppressGeneratorTimestamp() )
|
||||
.typeFactory( typeFactory )
|
||||
.elementUtils( elementUtils )
|
||||
.builtInMethods( new HashSet<BuiltInMethod>( usedBuiltInMethods ) )
|
||||
.build();
|
||||
|
||||
usedBuiltInMethods.clear();
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@ -582,7 +587,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
// then try BuiltInMethods
|
||||
if ( propertyMappingMethod == null ) {
|
||||
propertyMappingMethod = getMappingMethodReference(
|
||||
getBestMatch( method, mappedElement, builtInMethods, sourceType, targetType ),
|
||||
getBestMatch( method, mappedElement, builtInMethods.getBuiltInMethods(), sourceType, targetType ),
|
||||
targetType,
|
||||
dateFormat );
|
||||
}
|
||||
@ -639,7 +644,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
// then try BuiltInMethods
|
||||
if ( elementMappingMethod == null ) {
|
||||
elementMappingMethod = getMappingMethodReference(
|
||||
getBestMatch( method, "collection element", builtInMethods, sourceElementType,
|
||||
getBestMatch( method, "collection element", builtInMethods.getBuiltInMethods(), sourceElementType,
|
||||
targetElementType ),
|
||||
targetElementType,
|
||||
dateFormat );
|
||||
@ -695,7 +700,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
// then try BuiltInMethods
|
||||
if ( keyMappingMethod == null ) {
|
||||
keyMappingMethod = getMappingMethodReference(
|
||||
getBestMatch( method, "map key", builtInMethods, sourceKeyType, targetKeyType ),
|
||||
getBestMatch( method, "map key", builtInMethods.getBuiltInMethods(), sourceKeyType, targetKeyType ),
|
||||
targetKeyType,
|
||||
keyDateFormat );
|
||||
}
|
||||
@ -708,7 +713,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
// then try BuiltInMethods
|
||||
if ( valueMappingMethod == null ) {
|
||||
valueMappingMethod = getMappingMethodReference(
|
||||
getBestMatch( method, "map value", builtInMethods, sourceValueType, targetValueType ),
|
||||
getBestMatch( method, "map value", builtInMethods.getBuiltInMethods(), sourceValueType, targetValueType ),
|
||||
targetValueType,
|
||||
valueDateFormat );
|
||||
}
|
||||
@ -844,7 +849,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
|
||||
private MethodReference getMappingMethodReference( BuiltInMethod method, Type returnType, String dateFormat ) {
|
||||
if ( method != null ) {
|
||||
usedBuiltInMethods.add( method );
|
||||
virtualMethods.add( new VirtualMappingMethod( method ) );
|
||||
ConversionContext ctx = new DefaultConversionContext( typeFactory, returnType, dateFormat );
|
||||
return new MethodReference( method, ctx );
|
||||
}
|
||||
|
@ -41,13 +41,9 @@ import org.mapstruct.ap.writer.Writable.Context;
|
||||
*/
|
||||
public class FreeMarkerModelElementWriter {
|
||||
|
||||
public void write(Writable writable, Context context, Writer writer) throws Exception {
|
||||
write( writable, writable.getClass().getName() + ".ftl", context, writer );
|
||||
}
|
||||
|
||||
public void write(Writable writable, String templateName, Context context, Writer writer) throws Exception {
|
||||
public void write(FreeMarkerWritable writable, Context context, Writer writer) throws Exception {
|
||||
Configuration configuration = context.get( Configuration.class );
|
||||
Template template = configuration.getTemplate( templateName );
|
||||
Template template = configuration.getTemplate( writable.getTemplateName() );
|
||||
template.process(
|
||||
new ExternalParamsTemplateModel(
|
||||
new BeanModel( writable, BeansWrapper.getDefaultInstance() ),
|
||||
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright 2012-2014 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.writer;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* A {@link Writable} which uses the FreeMarker template engine to generate the output.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
public abstract class FreeMarkerWritable implements Writable {
|
||||
|
||||
@Override
|
||||
public void write(Context context, Writer writer) throws Exception {
|
||||
new FreeMarkerModelElementWriter().write( this, context, writer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the template to be used for a specific writable type. By default, the fully-qualified class
|
||||
* name of the given model element type, appended with the extension {@code *.ftl} is used as template file name,
|
||||
* but this can be customized by overriding this method if required.
|
||||
*
|
||||
* @return the name of the template. Must not be {@code null}.
|
||||
*/
|
||||
protected String getTemplateName() {
|
||||
return getClass().getName() + ".ftl";
|
||||
}
|
||||
}
|
@ -40,9 +40,4 @@ import ${importedType.fullyQualifiedName};
|
||||
|
||||
<#nt> <@includeModel object=mappingMethod/>
|
||||
</#list>
|
||||
|
||||
<#list builtInMethods as builtInMethod>
|
||||
|
||||
<#nt> <@includeModel object=builtInMethod/>
|
||||
</#list>
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user