fuliang 发表于 2013-1-15 02:57:52

代码生成技术学习之二 JMerger

代码自动生成,生成的代码许多时候需要修改,以满足我们的需求,而修改的代码我们希望重新生成代码的时候不被覆盖,那就需要一种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/
上面有更详细的介绍,但代码使用的版本有点老。
页: [1]
查看完整版本: 代码生成技术学习之二 JMerger