#109 Breaking up cycle between "model" and "writer" packages by introducing Writable interface

This commit is contained in:
Gunnar Morling 2014-01-25 11:39:19 +01:00
parent 21ed656348
commit 4d4f55a162
16 changed files with 109 additions and 106 deletions

View File

@ -1,39 +0,0 @@
/**
* 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.io.Writer;
import org.mapstruct.ap.writer.FreeMarkerModelElementWriter;
/**
* Default implementation of {@link ModelElement} which writes model elements
* 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.
*
* @author Gunnar Morling
*/
public abstract class AbstractModelElement implements ModelElement {
@Override
public void write(Context context, Writer writer) throws Exception {
new FreeMarkerModelElementWriter().write( this, context, writer );
}
}

View File

@ -18,13 +18,17 @@
*/ */
package org.mapstruct.ap.model; package org.mapstruct.ap.model;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.util.Collections; /**
* Represents a Java 5 annotation.
*
* @author Gunnar Morling
*/
public class Annotation extends ModelElement {
public class Annotation extends AbstractModelElement { private final Type type;
private Type type;
public Annotation(Type type) { public Annotation(Type type) {
this.type = type; this.type = type;
@ -36,6 +40,6 @@ public class Annotation extends AbstractModelElement {
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
return Collections.asSet( type ); return Collections.singleton( type );
} }
} }

View File

@ -30,7 +30,7 @@ import org.mapstruct.ap.util.Strings;
* @author Gunnar Morling * @author Gunnar Morling
* @author Andreas Gudian * @author Andreas Gudian
*/ */
public class AnnotationMapperReference extends AbstractModelElement implements MapperReference { public class AnnotationMapperReference extends MapperReference {
private final Annotation annotation; private final Annotation annotation;
private final Type type; private final Type type;

View File

@ -31,7 +31,7 @@ import org.mapstruct.ap.util.TypeFactory;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class DefaultMapperReference extends AbstractModelElement implements MapperReference { public class DefaultMapperReference extends MapperReference {
private final Type type; private final Type type;
private final boolean isAnnotatedMapper; private final boolean isAnnotatedMapper;

View File

@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import javax.annotation.Generated; import javax.annotation.Generated;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
@ -37,7 +36,7 @@ import org.mapstruct.ap.util.TypeFactory;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class Mapper extends AbstractModelElement { public class Mapper extends ModelElement {
private static final String IMPLEMENTATION_SUFFIX = "Impl"; private static final String IMPLEMENTATION_SUFFIX = "Impl";

View File

@ -19,12 +19,16 @@
package org.mapstruct.ap.model; package org.mapstruct.ap.model;
/** /**
* A reference to another mapper class, which itself may be generated or * A reference to another mapper class, which itself may be generated or hand-written.
* hand-written.
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public interface MapperReference extends ModelElement { public abstract class MapperReference extends ModelElement {
Type getMapperType(); /**
* Returns the type of the referenced mapper
*
* @return the type of the referenced mapper
*/
public abstract Type getMapperType();
} }

View File

@ -32,7 +32,7 @@ import org.mapstruct.ap.util.Strings;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public abstract class MappingMethod extends AbstractModelElement { public abstract class MappingMethod extends ModelElement {
private final String name; private final String name;
private final List<Parameter> parameters; private final List<Parameter> parameters;

View File

@ -21,47 +21,30 @@ package org.mapstruct.ap.model;
import java.io.Writer; import java.io.Writer;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.writer.FreeMarkerModelElementWriter;
import org.mapstruct.ap.writer.Writable;
/** /**
* A model element with the ability to write itself into a given {@link Writer}. * 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.
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public interface ModelElement { public abstract class ModelElement implements Writable {
/** @Override
* Passed to {@link ModelElement}, providing access to additional data public void write(Context context, Writer writer) throws Exception {
* specific to a given implementation of the model serialization mechanism. new FreeMarkerModelElementWriter().write( this, context, writer );
*
* @author Gunnar Morling
*/
interface Context {
/**
* Retrieves the object with the given type from this context.
*
* @param type The type of the object to retrieve from this context.
*
* @return The object with the given type from this context.
*/
<T> T get(Class<T> type);
} }
/** /**
* Writes this model element to the given writer. * Returns a set containing those {@link Type}s referenced by this model element for which an import statement needs
* to be declared.
* *
* @param context Provides additional data specific to the used implementation * @return A set with type referenced by this model element. Must not be {@code null}.
* of the model serialization mechanism.
* @param writer The writer to write this model to. Must not be closed by
* implementations.
*/ */
void write(Context context, Writer writer) throws Exception; public abstract Set<Type> getImportTypes();
/**
* Returns a set containing those {@link Type}s referenced by this model
* element for which an import statement needs to be declared.
*
* @return A set with type referenced by this model element. Must not be
* {@code null.}
*/
Set<Type> getImportTypes();
} }

View File

@ -27,7 +27,7 @@ import org.mapstruct.ap.util.Collections;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class Parameter extends AbstractModelElement { public class Parameter extends ModelElement {
private final String name; private final String name;
private final Type type; private final Type type;

View File

@ -29,7 +29,7 @@ import java.util.Set;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class PropertyMapping extends AbstractModelElement { public class PropertyMapping extends ModelElement {
private final String sourceBeanName; private final String sourceBeanName;
private final String sourceName; private final String sourceName;

View File

@ -43,7 +43,7 @@ import org.mapstruct.ap.util.TypeFactory;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class Type extends AbstractModelElement implements Comparable<Type> { public class Type extends ModelElement implements Comparable<Type> {
private final String packageName; private final String packageName;
private final String name; private final String name;

View File

@ -28,7 +28,7 @@ import java.util.Set;
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
public class TypeConversion extends AbstractModelElement { public class TypeConversion extends ModelElement {
private final Set<Type> importTypes; private final Set<Type> importTypes;
private final List<Type> exceptionTypes; private final List<Type> exceptionTypes;

View File

@ -29,11 +29,10 @@ import freemarker.template.Template;
import freemarker.template.TemplateHashModel; import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel; import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelException;
import org.mapstruct.ap.model.ModelElement; import org.mapstruct.ap.writer.Writable.Context;
import org.mapstruct.ap.model.ModelElement.Context;
/** /**
* Delegate for writing given {@link ModelElement}s into a {@link Writer} using * Delegate for writing given {@link Writable}s into a {@link Writer} using
* FreeMarker templates. Any parameters passed to the * FreeMarker templates. Any parameters passed to the
* {@link ModelIncludeDirective} in addition to element itself can be accessed * {@link ModelIncludeDirective} in addition to element itself can be accessed
* from within the template using the {@code ext} pseudo-element. * from within the template using the {@code ext} pseudo-element.
@ -42,16 +41,16 @@ import org.mapstruct.ap.model.ModelElement.Context;
*/ */
public class FreeMarkerModelElementWriter { public class FreeMarkerModelElementWriter {
public void write(ModelElement modelElement, Context context, Writer writer) throws Exception { public void write(Writable writable, Context context, Writer writer) throws Exception {
write( modelElement, modelElement.getClass().getName() + ".ftl", context, writer ); write( writable, writable.getClass().getName() + ".ftl", context, writer );
} }
public void write(ModelElement modelElement, String templateName, Context context, Writer writer) throws Exception { public void write(Writable writable, 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( template.process(
new ExternalParamsTemplateModel( new ExternalParamsTemplateModel(
new BeanModel( modelElement, BeansWrapper.getDefaultInstance() ), new BeanModel( writable, BeansWrapper.getDefaultInstance() ),
new SimpleMapModel( context.get( Map.class ), BeansWrapper.getDefaultInstance() ) new SimpleMapModel( context.get( Map.class ), BeansWrapper.getDefaultInstance() )
), ),
writer writer

View File

@ -29,12 +29,11 @@ import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
import freemarker.template.TemplateModel; import freemarker.template.TemplateModel;
import org.mapstruct.ap.model.ModelElement;
import org.mapstruct.ap.writer.ModelWriter.DefaultModelElementWriterContext; import org.mapstruct.ap.writer.ModelWriter.DefaultModelElementWriterContext;
/** /**
* A {@link TemplateDirectiveModel} which allows to recursively write a graph of * A {@link TemplateDirectiveModel} which allows to recursively write a graph of
* {@link ModelElement}s, with each element using its own template. Elements are * {@link Writable}s, with each element using its own template. Elements are
* imported into the parent template by using this directive like so: * imported into the parent template by using this directive like so:
* {@code <@includeModel object=myProperty/>}. * {@code <@includeModel object=myProperty/>}.
* *
@ -53,7 +52,7 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
TemplateDirectiveBody body) TemplateDirectiveBody body)
throws TemplateException, IOException { throws TemplateException, IOException {
ModelElement modelElement = getModelElement( params ); Writable modelElement = getModelElement( params );
DefaultModelElementWriterContext context = createContext( params ); DefaultModelElementWriterContext context = createContext( params );
try { try {
@ -74,7 +73,7 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private ModelElement getModelElement(Map params) { private Writable getModelElement(Map params) {
if ( !params.containsKey( "object" ) ) { if ( !params.containsKey( "object" ) ) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Object to be included must be passed to this directive via the 'object' parameter" "Object to be included must be passed to this directive via the 'object' parameter"
@ -89,11 +88,11 @@ public class ModelIncludeDirective implements TemplateDirectiveModel {
); );
} }
if ( !( objectModel.getWrappedObject() instanceof ModelElement ) ) { if ( !( objectModel.getWrappedObject() instanceof Writable ) ) {
throw new IllegalArgumentException( "Given object isn't a ModelElement:" + objectModel.getWrappedObject() ); throw new IllegalArgumentException( "Given object isn't a ModelElement:" + objectModel.getWrappedObject() );
} }
return (ModelElement) objectModel.getWrappedObject(); return (Writable) objectModel.getWrappedObject();
} }
/** /**

View File

@ -26,8 +26,7 @@ import javax.tools.JavaFileObject;
import freemarker.log.Logger; import freemarker.log.Logger;
import freemarker.template.Configuration; import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper; import freemarker.template.DefaultObjectWrapper;
import org.mapstruct.ap.model.ModelElement; import org.mapstruct.ap.writer.Writable.Context;
import org.mapstruct.ap.model.ModelElement.Context;
/** /**
* Writes Java source files based on given mapper models, using a FreeMarker * Writes Java source files based on given mapper models, using a FreeMarker
@ -60,7 +59,7 @@ public class ModelWriter {
); );
} }
public void writeModel(JavaFileObject sourceFile, ModelElement model) { public void writeModel(JavaFileObject sourceFile, Writable model) {
try { try {
BufferedWriter writer = new BufferedWriter( new IndentationCorrectingWriter( sourceFile.openWriter() ) ); BufferedWriter writer = new BufferedWriter( new IndentationCorrectingWriter( sourceFile.openWriter() ) );

View File

@ -0,0 +1,55 @@
/**
* 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;
/**
* An element with the ability to write itself into a given {@link Writer}.
*
* @author Gunnar Morling
*/
public interface Writable {
/**
* Passed to {@link Writable}, providing access to additional data specific to a given implementation of the model
* serialization mechanism.
*
* @author Gunnar Morling
*/
interface Context {
/**
* Retrieves the object with the given type from this context.
*
* @param type The type of the object to retrieve from this context.
*
* @return The object with the given type from this context.
*/
<T> T get(Class<T> type);
}
/**
* Writes this element to the given writer.
*
* @param context Provides additional data specific to the used implementation of the serialization mechanism.
* @param writer The writer to write this element to. Must not be closed by implementations.
*/
void write(Context context, Writer writer) throws Exception;
}