mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#44 Creating template for writing MappingMethodReferences, enhancing templating mechanism to pass additional objects to <includeModel/> directive
This commit is contained in:
parent
ac9859c38d
commit
6e9abacdd6
@ -19,15 +19,24 @@
|
||||
package org.mapstruct.ap.writer;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import freemarker.ext.beans.BeanModel;
|
||||
import freemarker.ext.beans.BeansWrapper;
|
||||
import freemarker.ext.beans.SimpleMapModel;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateHashModel;
|
||||
import freemarker.template.TemplateModel;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import org.mapstruct.ap.model.ModelElement;
|
||||
import org.mapstruct.ap.model.ModelElement.Context;
|
||||
|
||||
/**
|
||||
* Delegate for writing given {@link ModelElements} into a {@link Writer} using
|
||||
* FreeMarker templates.
|
||||
* Delegate for writing given {@link ModelElement}s into a {@link Writer} using
|
||||
* FreeMarker templates. Any parameters passed to the
|
||||
* {@link ModelIncludeDirective} in addition to element itself can be accessed
|
||||
* from within the template using the {@code ext} pseudo-element.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
@ -39,8 +48,39 @@ public class FreeMarkerModelElementWriter {
|
||||
|
||||
public void write(ModelElement modelElement, String templateName, Context context, Writer writer) throws Exception {
|
||||
Configuration configuration = context.get( Configuration.class );
|
||||
|
||||
Template template = configuration.getTemplate( templateName );
|
||||
template.process( modelElement, writer );
|
||||
template.process(
|
||||
new ExternalParamsTemplateModel(
|
||||
new BeanModel( modelElement, BeansWrapper.getDefaultInstance() ),
|
||||
new SimpleMapModel( context.get( Map.class ), BeansWrapper.getDefaultInstance() )
|
||||
),
|
||||
writer
|
||||
);
|
||||
}
|
||||
|
||||
private static class ExternalParamsTemplateModel implements TemplateHashModel {
|
||||
|
||||
private final BeanModel object;
|
||||
private final SimpleMapModel extParams;
|
||||
|
||||
public ExternalParamsTemplateModel(BeanModel object, SimpleMapModel extParams) {
|
||||
this.object = object;
|
||||
this.extParams = extParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateModel get(String key) throws TemplateModelException {
|
||||
if ( key.equals( "ext" ) ) {
|
||||
return extParams;
|
||||
}
|
||||
else {
|
||||
return object.get( key );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() throws TemplateModelException {
|
||||
return object.isEmpty() && extParams.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,12 @@
|
||||
package org.mapstruct.ap.writer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.ext.beans.BeanModel;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateDirectiveBody;
|
||||
import freemarker.template.TemplateDirectiveModel;
|
||||
import freemarker.template.TemplateException;
|
||||
@ -40,10 +42,10 @@ import org.mapstruct.ap.writer.ModelWriter.DefaultModelElementWriterContext;
|
||||
*/
|
||||
public class ModelIncludeDirective implements TemplateDirectiveModel {
|
||||
|
||||
private DefaultModelElementWriterContext context;
|
||||
private final Configuration configuration;
|
||||
|
||||
public ModelIncludeDirective(DefaultModelElementWriterContext context) {
|
||||
this.context = context;
|
||||
public ModelIncludeDirective(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,13 +53,8 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
|
||||
TemplateDirectiveBody body)
|
||||
throws TemplateException, IOException {
|
||||
|
||||
Object wrappedObject = ( (BeanModel) params.get( "object" ) ).getWrappedObject();
|
||||
|
||||
if ( !( wrappedObject instanceof ModelElement ) ) {
|
||||
throw new IllegalArgumentException( "Given object isn't a ModelElement:" + wrappedObject );
|
||||
}
|
||||
|
||||
ModelElement modelElement = (ModelElement) wrappedObject;
|
||||
ModelElement modelElement = getModelElement( params );
|
||||
DefaultModelElementWriterContext context = createContext( params );
|
||||
|
||||
try {
|
||||
modelElement.write( context, env.getOut() );
|
||||
@ -75,4 +72,48 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private ModelElement getModelElement(Map params) {
|
||||
if ( !params.containsKey( "object" ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Object to be included must be passed to this directive via the 'object' parameter"
|
||||
);
|
||||
}
|
||||
|
||||
BeanModel objectModel = (BeanModel) params.get( "object" );
|
||||
|
||||
if ( objectModel == null ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Object passed to this directive via the 'object' parameter must not be null"
|
||||
);
|
||||
}
|
||||
|
||||
if ( !( objectModel.getWrappedObject() instanceof ModelElement ) ) {
|
||||
throw new IllegalArgumentException( "Given object isn't a ModelElement:" + objectModel.getWrappedObject() );
|
||||
}
|
||||
|
||||
return (ModelElement) objectModel.getWrappedObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a writer context providing access to the FreeMarker
|
||||
* {@link Configuration} and a map with any additional parameters passed to
|
||||
* the directive.
|
||||
*
|
||||
* @param params The parameter map passed to this directive.
|
||||
*
|
||||
* @return A writer context.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private DefaultModelElementWriterContext createContext(Map params) {
|
||||
Map<String, Object> ext = new HashMap<String, Object>( params );
|
||||
ext.remove( "object" );
|
||||
|
||||
Map<Class<?>, Object> values = new HashMap<Class<?>, Object>();
|
||||
values.put( Configuration.class, configuration );
|
||||
values.put( Map.class, ext );
|
||||
|
||||
return new DefaultModelElementWriterContext( values );
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class ModelWriter {
|
||||
CONFIGURATION.setObjectWrapper( new DefaultObjectWrapper() );
|
||||
CONFIGURATION.setSharedVariable(
|
||||
"includeModel",
|
||||
new ModelIncludeDirective( new DefaultModelElementWriterContext( CONFIGURATION ) )
|
||||
new ModelIncludeDirective( CONFIGURATION )
|
||||
);
|
||||
}
|
||||
|
||||
@ -64,7 +64,9 @@ public class ModelWriter {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter( sourceFile.openWriter() );
|
||||
|
||||
model.write( new DefaultModelElementWriterContext( CONFIGURATION ), writer );
|
||||
Map<Class<?>, Object> values = new HashMap<Class<?>, Object>();
|
||||
values.put( Configuration.class, CONFIGURATION );
|
||||
model.write( new DefaultModelElementWriterContext( values ), writer );
|
||||
|
||||
writer.flush();
|
||||
writer.close();
|
||||
@ -85,10 +87,10 @@ public class ModelWriter {
|
||||
*/
|
||||
static class DefaultModelElementWriterContext implements Context {
|
||||
|
||||
private Map<Class<?>, Object> values = new HashMap<Class<?>, Object>();
|
||||
private Map<Class<?>, Object> values;
|
||||
|
||||
private DefaultModelElementWriterContext(Configuration configuration) {
|
||||
values.put( Configuration.class, configuration );
|
||||
DefaultModelElementWriterContext(Map<Class<?>, Object> values) {
|
||||
this.values = new HashMap<Class<?>, Object>( values );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,7 +42,7 @@
|
||||
</#list>
|
||||
</#if>
|
||||
<#else>
|
||||
${targetType.name?uncap_first}.add( ${elementMappingMethod.name}( ${sourceType.typeParameters[0].name?uncap_first} ) );
|
||||
${targetType.name?uncap_first}.add( <@includeModel object=elementMappingMethod input="${sourceType.typeParameters[0].name?uncap_first}"/> );
|
||||
</#if>
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
<#--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<#if declaringMapper??>${declaringMapper.name?uncap_first}.</#if>${name}( ${ext.input} )
|
@ -20,7 +20,7 @@
|
||||
-->
|
||||
<#-- a) invoke mapping method -->
|
||||
<#if mappingMethod??>
|
||||
${targetBeanName}.${targetAccessorName}( <#if mappingMethod.declaringMapper??>${mappingMethod.declaringMapper.name?uncap_first}.</#if>${mappingMethod.name}( ${sourceBeanName}.${sourceAccessorName}() ) );
|
||||
${targetBeanName}.${targetAccessorName}( <@includeModel object=mappingMethod input="${sourceBeanName}.${sourceAccessorName}()"/> );
|
||||
<#-- b) simple conversion -->
|
||||
<#elseif conversion??>
|
||||
<#if sourceType.primitive == false>
|
||||
|
Loading…
x
Reference in New Issue
Block a user