5

I am working on a project that will have several Java classes that are very similar to each other, and that I would like to generate from XML files. What I would like to be able to do is change the Eclipse build process to do something like this:

  • Compile the code generator
  • Run the code generator, converting the XML to Java
  • Compile the rest of the project

I could do this all manually but I would prefer to be able to have Eclipse do it all for me.

Example

I want to be able to take a source XML file that looks like this:

<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>

and have it give me something similar to the following (in separate files as appropriate):

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();
    }
}
4

2 に答える 2

4

これはまさに、Model to Text (M2T) プロジェクトの JET コンポーネントが作成された目的です。実際、プロジェクト、.classpath、および JET で必要なその他のファイルを作成することもできます。

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>

次の 3 つの Java ファイルを含む com.lacqui.commands という名前の完全な 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();
    }
}
于 2012-08-10T15:34:05.990 に答える
1

JaxB を見てみたいと思うかもしれません。

簡単に見たい場合は、Lars Vogel が簡単なチュートリアルを作成しました。
JAXB チュートリアル

また、ここに xml アンマーシャリングのベンチマーク テストがあります。
Java での XML アンマーシャリング ベンチマーク: JAXB vs Stax vs Woodstox

于 2012-08-10T15:46:45.960 に答える