|
|
代码自动生成,生成的代码许多时候需要修改,以满足我们的需求,而修改的代码我们希望重新生成代码的时候不被覆盖,那就需要一种Merge技术。JMerger和JET模板是在EMF代码生成中使用的关键技术。下面我们看一下一个使用JMerger的例子:
两个java文件:
HelloSrc.java
package hello;public class Hello{ public void say(){ System.out.println("hello"); } /** * @generated */ public void sayHelloTo(String name){ System.out.println("Hello," + name); } public void test(){ }}
HelloTarget.java
package hello;public class Hello { public void say(){ System.out.println("hello world"); } /** * @generated */ public void sayHelloTo(String name){ System.out.println(name); }}
我们使用JMerger来合并覆盖原先生成的的方法//@generated标记的方法,而我们
自己定义的方法和去掉@generated的的方法则不被覆盖。
我们需要增加某种机制来告诉 JMerge 有些方法已经被修改过了,因此这些方法不应该被重写。要实现这种功能,可以使用 <merge:dictionaryPattern> 元素。 merge:dictionaryPattern 允许您使用正则表达式来区分 Java 元素:
<?xml version="1.0" encoding="UTF-8"?><merge:options xmlns:merge="http://www.eclipse.org/org/eclipse/emf/codegen/jmerge/Options"> <merge:dictionaryPattern name="generatedMember" select="Member/getComment" match= "s*@s*(gen)erateds*"/> <merge:pull targetMarkup="^gen$" sourceGet="Method/getBody" targetPut="Method/setBody"/> </merge:options>
dictionaryPattern 定义了一个正则表达式,它可以匹配注释中包含 " @generated " 的成员。 select 属性列出了要对这个成员的哪些部分与在 match 属性中给出的正则表达式进行比较。 dictionaryPattern 是由字符串 gen 定义的,它就是 match 属性值中圆括号中的内容。merge:pull 元素多了一个附加属性 targetMarkup 。这个属性可以匹配 dictionaryPattern ,它必须在应用合并规则之前对目标代码进行匹配。此处,我们正在检查的是目标代码,而不是源代码,因此用户可以定制这些代码。当用户删除注释中的 " @generated " 标签时, dictionaryPattern 就不会与目标代码匹配,因此就不会合并这个方法体
package hello;import java.io.File;import java.io.FileInputStream;import java.util.HashMap;import java.util.Map;import org.eclipse.emf.codegen.merge.java.JControlModel;import org.eclipse.emf.codegen.merge.java.JMerger;import org.eclipse.emf.codegen.merge.java.facade.ast.ASTFacadeHelper;import org.eclipse.jdt.core.JavaCore;import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;public class JMergerTest{ public static void merge( File src, File target ) { JControlModel model = new JControlModel(); ASTFacadeHelper astFacadeHelper = new ASTFacadeHelper() { Map<String, String> options; @SuppressWarnings("unchecked") @Override public Map getJavaCoreOptions() { if( options == null ) { options = new HashMap<String, String>(); options.put( JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_6 ); options.put( JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6 ); options.put( JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_6 ); options.put( JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR ); options.put( JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR ); options.put( JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED ); options.put( JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED ); Map cfo = DefaultCodeFormatterConstants.getEclipseDefaultSettings(); options.putAll( cfo ); options.put( DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_AFTER_PACKAGE, "1" ); } return options; } }; String mergexml = JMergerTest.class.getResource( "merge.xml" ).getFile(); model.initialize( astFacadeHelper, mergexml ); JMerger jMerger = new JMerger(model); try { jMerger.setSourceCompilationUnit( jMerger.createCompilationUnitForInputStream( new FileInputStream( src ))); jMerger.setTargetCompilationUnit( jMerger.createCompilationUnitForInputStream( new FileInputStream(target))); } catch( Exception e ) { e.printStackTrace(); } jMerger.merge(); String contents = jMerger.getTargetCompilationUnit().getContents(); System.out.println(contents); } public static void main( String[] args ) { File src = new File("HelloSrc.java" ); File target = new File("HelloTarget.java"); JMergerTest.merge( src, target ); }}
结果:
package hello;public class Hello { public void say(){ System.out.println("hello world"); } /** * @generated */ public void sayHelloTo(String name){ System.out.println("Hello," + name); } public void test(){ }}
参考http://www.ibm.com/developerworks/library/os-ecemf3/
上面有更详细的介绍,但代码使用的版本有点老。 |
|