在 Eclipse 中从 XML 生成 Java 代码

Posted

技术标签:

【中文标题】在 Eclipse 中从 XML 生成 Java 代码【英文标题】:Generating Java code from XML in Eclipse 【发布时间】:2012-08-07 22:35:03 【问题描述】:

我正在开发一个项目,该项目将包含多个彼此非常相似的 Java 类,并且我想从 XML 文件生成这些类。我想要做的是改变 Eclipse 构建过程来做这样的事情:

编译代码生成器 运行代码生成器,将 XML 转换为 Java 编译项目的其余部分

我可以手动完成这一切,但我更愿意让 Eclipse 为我完成这一切。

示例

我希望能够获取如下所示的源 XML 文件:

<command-list>
    <command name="DATE" />
    <command name="GROUP">
        <capability "READER" />
        <argument "groupname" />
    </command>
    <command name="ARTICLE">
        <capability "READER" />
        <argument "message-id" optional="true" />
    </command>
</command-list>

并让它给我类似于以下内容(在单独的文件中酌情):

public class Date extends Command 
    public ResponseCode execute() 
        Server srv = getServer();
        srv.send("DATE");
        return srv.getResponse();
    


public class Group extends Command 
    public ResponseCode execute() 
        Server srv = getServer();
        if (srv.hasCapability(Capabilities.READER) == false) 
            Log.debug("Attempting non-available capability: READER");
        
        String groupname = getArgument("groupname");
        if (groupname == null) 
             throw new InvalidArgumentException("Require groupname");
        
        String command = "GROUP";
        if (groupname != null) command += " " + groupname;
        srv.send(command);
        return srv.getResponse();
    


public class Article extends Command 
    public ResponseCode execute() 
        Server srv = getServer();
        if (srv.hasCapability(Capabilities.READER) == false) 
            Log.debug("Attempting non-available capability: READER");
        
        String messageId = getArgument("messageId");
        String command = "ARTICLE";
        if (messageId != null) command += " " + messageId;
        srv.send(command);
        return srv.getResponse();
    

【问题讨论】:

您为什么不编写一个批处理文件/shell 脚本来为您完成所有这些工作?一行两个参数 -> 完成!我问这个是因为我个人不知道你会如何(如果可能的话)在 Eclipse 中做到这一点,而且看起来你在这里是为了方便使用。 我希望它成为构建过程的一部分,这样如果我更改我的模板或 XML,它将重新生成 @thatidiotguy 您可以将 ant 脚本作为项目属性的一部分集成到构建过程中,它位于“构建器”下。不知道有没有batch/shell脚本支持,不过我也没看。 【参考方案1】:

这正是模型到文本 (M2T) 项目中的 JET 组件的用途。事实上,您甚至可以使用 JET 创建项目、.classpath 和您需要的任何其他文件。

Jet 模板如下。请注意,这些模板的名称必须与所示完全相同。

/templates/main.jet

<%@taglib prefix="ws" id="org.eclipse.jet.workspaceTags" %>
<%-- Main entry point for com.lacqui.command.xform --%>

<%-- 
  Let c:iterate tags set the XPath context object.
  For 100% compatibility with JET 0.9.x or earlier, remove this statement
 --%>
<c:setVariable var="org.eclipse.jet.taglib.control.iterateSetsContext" select="true()"/>

    <c:setVariable select="/command-list" var="command-list" />

    --- traverse input model, performing calculations and storing 
    --- the results as model annotations via c:set tag 

    <c:set select="$command-list" name="project">com.lacqui.commands</c:set>
    <c:set select="$command-list" name="commandPkg">com.lacqui.commands</c:set>
    <c:set select="$command-list" name="commandDir"><c:get select="translate($command-list/@commandPkg,'.','/')" /></c:set>

    <c:iterate select="$command-list/command" var="command" >

            - Derive the class name from the name of the command

        <c:set select="$command" name="classname"><c:get select="camelCase($command/@name)" />Command</c:set>

        <c:iterate select="$command/argument" var="argument">

            <c:if test="not($argument/@optional)">
                <c:set select="$argument" name="optional">false</c:set>
            </c:if>

        </c:iterate>

    </c:iterate>

   --- traverse annotated model, performing text generation actions 
   --- such as ws:file, ws:folder and ws:project 

   <ws:project name="$command-list/@project" />
   <ws:file template="templates/project.jet" path="$command-list/@project/.project"  />
   <ws:file template="templates/classpath.jet" path="$command-list/@project/.classpath"/>

    <c:iterate select="$command-list/command" var="command" >

        <ws:file template="templates/class.jet" path="$command-list/@project/src/$command-list/@commandDir/$command/@classname.java" replace="true"/>

    </c:iterate>

/templates/classpath.jet

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="output" path="bin"/>
</classpath>

/templates/project.jet

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
    <name><c:get select="$command-list/@project" /></name>
    <comment></comment>
    <projects>
    </projects>
    <buildSpec>
        <buildCommand>
            <name>org.eclipse.jdt.core.javabuilder</name>
            <arguments>
            </arguments>
        </buildCommand>
    </buildSpec>
    <natures>
        <nature>org.eclipse.jdt.core.javanature</nature>
    </natures>
</projectDescription>

/templates/class.jet

package <c:get select="$command-list/@commandPkg" />;

public class <c:get select="$command/@classname" /> extends Command 
    public ResponseCode execute() 
        Server srv = getServer();
<c:iterate select="$command/capability" var="capability">

        if (srv.hasCapability(Capabilities.<c:get select="$capability/@name"/>) == false) 
            Log.debug("Attempting non-available capability: <c:get select="$capability/@name"/>");
        
</c:iterate>        
<c:iterate select="$command/argument" var="argument">

        String <c:get select="$argument/@name"/> = getArgument("<c:get select="$argument/@name"/>");
<c:if test="$argument/@optional = 'false'" >
        if (<c:get select="$argument/@name"/> == null) 
             throw new InvalidArgumentException("Require <c:get select="$argument/@name"/>");
        
</c:if>
</c:iterate>        

        String command = "GROUP";
<c:iterate select="$command/argument" var="argument">
        if (<c:get select="$argument/@name"/> != null) command += " -<c:get select="$argument/@name"/> " + <c:get select="$argument/@name"/>;
</c:iterate>       

        srv.send(command);
        return srv.getResponse();
    

并使用此模型:

<command-list>
    <command name="DATE" />
    <command name="GROUP">
        <capability name="LOGGER" />
        <capability name="AUTHENTICATOR" />
        <argument name="groupname" />
    </command>
    <command name="ARTICLE">
        <capability name="READER" />
        <argument name="article-id" optional="false" />
        <argument name="message-id" optional="true" />
    </command>
</command-list>

给出一个名为 com.lacqui.commands 的完整 java 项目,其中包含三个 java 文件:

package com.lacqui.commands;

public class ArticleCommand extends Command 
    public ResponseCode execute() 
        Server srv = getServer();

        if (srv.hasCapability(Capabilities.READER) == false) 
            Log.debug("Attempting non-available capability: READER");
        

        String article-id = getArgument("article-id");
        if (article-id == null) 
             throw new InvalidArgumentException("Require article-id");
        

        String message-id = getArgument("message-id");

        String command = "GROUP";
        if (article-id != null) command += " -article-id " + article-id;
        if (message-id != null) command += " -message-id " + message-id;

        srv.send(command);
        return srv.getResponse();
    

还有这个:

package com.lacqui.commands;

public class GroupCommand extends Command 
    public ResponseCode execute() 
        Server srv = getServer();

        if (srv.hasCapability(Capabilities.LOGGER) == false) 
            Log.debug("Attempting non-available capability: LOGGER");
        

        if (srv.hasCapability(Capabilities.AUTHENTICATOR) == false) 
            Log.debug("Attempting non-available capability: AUTHENTICATOR");
        

        String groupname = getArgument("groupname");
        if (groupname == null) 
             throw new InvalidArgumentException("Require groupname");
        

        String command = "GROUP";
        if (groupname != null) command += " -groupname " + groupname;

        srv.send(command);
        return srv.getResponse();
    

【讨论】:

我没有尝试使用 XML 作为运行时数据格式 - 我使用它来简化我的源文件生成。 JET 是一种开发时间工具,可将代码、JSP、html、属性文件、Eclipse“点资源”等生成到 Eclipse 项目中(可能在创建和配置这些项目之后)。该资源生成由模型驱动,通常是 XML,但可以是任何格式,并且在运行时根本不使用该模型。所以 JET 在这里对你来说确实是一个很好的方法。在您的问题中发布示例课程,我可以发布您可能用来生成该课程的模板。 我的问题中有几个例子。 是的,这正是我要找的。谢谢。 如何让它在 Eclipse 中工作?我尝试按照此答案中的建议粘贴几个文件。创建了一个项目并在其上启用了 JET,并将 .jet 文件转储到“模板”文件夹中。但它给出的错误。我正在努力学习这一点,但不知道如何让它发挥作用。【参考方案2】:

您可能想看看 JaxB。

如果您想快速浏览一下,Lars Vogel 做了一个简单的教程。JAXB Tutorial

这里还有一个 xml 解组的基准测试。XML unmarshalling benchmark in Java: JAXB vs STax vs Woodstox

【讨论】:

我没有尝试使用 XML 作为运行时数据格式 - 我使用它来简化我的源文件生成。

以上是关于在 Eclipse 中从 XML 生成 Java 代码的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中从 XML DTD 生成对象模型

如何在 C# 中从数据表生成 XML

运行eclipse中怎样将mybatisgenerator.java里的自动生成bean文件

在 C# 中从 XML Schema 生成代码的限制是啥?

在 Eclipse 中从 jslint4java 中排除文件

如何在eclipse中从另一个java项目中读取项目的属性文件