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;
|
package org.mapstruct.ap.writer;
|
||||||
|
|
||||||
import java.io.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.Configuration;
|
||||||
import freemarker.template.Template;
|
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;
|
||||||
import org.mapstruct.ap.model.ModelElement.Context;
|
import org.mapstruct.ap.model.ModelElement.Context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate for writing given {@link ModelElements} into a {@link Writer} using
|
* Delegate for writing given {@link ModelElement}s into a {@link Writer} using
|
||||||
* FreeMarker templates.
|
* 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
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
@ -39,8 +48,39 @@ public class FreeMarkerModelElementWriter {
|
|||||||
|
|
||||||
public void write(ModelElement modelElement, String templateName, Context context, Writer writer) throws Exception {
|
public void write(ModelElement modelElement, String templateName, Context context, Writer writer) throws Exception {
|
||||||
Configuration configuration = context.get( Configuration.class );
|
Configuration configuration = context.get( Configuration.class );
|
||||||
|
|
||||||
Template template = configuration.getTemplate( templateName );
|
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;
|
package org.mapstruct.ap.writer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import freemarker.core.Environment;
|
import freemarker.core.Environment;
|
||||||
import freemarker.ext.beans.BeanModel;
|
import freemarker.ext.beans.BeanModel;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.TemplateDirectiveBody;
|
import freemarker.template.TemplateDirectiveBody;
|
||||||
import freemarker.template.TemplateDirectiveModel;
|
import freemarker.template.TemplateDirectiveModel;
|
||||||
import freemarker.template.TemplateException;
|
import freemarker.template.TemplateException;
|
||||||
@ -40,10 +42,10 @@ import org.mapstruct.ap.writer.ModelWriter.DefaultModelElementWriterContext;
|
|||||||
*/
|
*/
|
||||||
public class ModelIncludeDirective implements TemplateDirectiveModel {
|
public class ModelIncludeDirective implements TemplateDirectiveModel {
|
||||||
|
|
||||||
private DefaultModelElementWriterContext context;
|
private final Configuration configuration;
|
||||||
|
|
||||||
public ModelIncludeDirective(DefaultModelElementWriterContext context) {
|
public ModelIncludeDirective(Configuration configuration) {
|
||||||
this.context = context;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -51,13 +53,8 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
|
|||||||
TemplateDirectiveBody body)
|
TemplateDirectiveBody body)
|
||||||
throws TemplateException, IOException {
|
throws TemplateException, IOException {
|
||||||
|
|
||||||
Object wrappedObject = ( (BeanModel) params.get( "object" ) ).getWrappedObject();
|
ModelElement modelElement = getModelElement( params );
|
||||||
|
DefaultModelElementWriterContext context = createContext( params );
|
||||||
if ( !( wrappedObject instanceof ModelElement ) ) {
|
|
||||||
throw new IllegalArgumentException( "Given object isn't a ModelElement:" + wrappedObject );
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelElement modelElement = (ModelElement) wrappedObject;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
modelElement.write( context, env.getOut() );
|
modelElement.write( context, env.getOut() );
|
||||||
@ -75,4 +72,48 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
|
|||||||
throw new RuntimeException( e );
|
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.setObjectWrapper( new DefaultObjectWrapper() );
|
||||||
CONFIGURATION.setSharedVariable(
|
CONFIGURATION.setSharedVariable(
|
||||||
"includeModel",
|
"includeModel",
|
||||||
new ModelIncludeDirective( new DefaultModelElementWriterContext( CONFIGURATION ) )
|
new ModelIncludeDirective( CONFIGURATION )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,9 @@ public class ModelWriter {
|
|||||||
try {
|
try {
|
||||||
BufferedWriter writer = new BufferedWriter( sourceFile.openWriter() );
|
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.flush();
|
||||||
writer.close();
|
writer.close();
|
||||||
@ -85,10 +87,10 @@ public class ModelWriter {
|
|||||||
*/
|
*/
|
||||||
static class DefaultModelElementWriterContext implements Context {
|
static class DefaultModelElementWriterContext implements Context {
|
||||||
|
|
||||||
private Map<Class<?>, Object> values = new HashMap<Class<?>, Object>();
|
private Map<Class<?>, Object> values;
|
||||||
|
|
||||||
private DefaultModelElementWriterContext(Configuration configuration) {
|
DefaultModelElementWriterContext(Map<Class<?>, Object> values) {
|
||||||
values.put( Configuration.class, configuration );
|
this.values = new HashMap<Class<?>, Object>( values );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
</#list>
|
</#list>
|
||||||
</#if>
|
</#if>
|
||||||
<#else>
|
<#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>
|
</#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 -->
|
<#-- a) invoke mapping method -->
|
||||||
<#if mappingMethod??>
|
<#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 -->
|
<#-- b) simple conversion -->
|
||||||
<#elseif conversion??>
|
<#elseif conversion??>
|
||||||
<#if sourceType.primitive == false>
|
<#if sourceType.primitive == false>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user