在Eclipse中从XML生成Java代码
我正在研究一个项目,该项目将具有多个彼此非常类似的Java类,并且我希望从XML文件生成这些类。我希望能够做的是改变Eclipse构建过程中做这样的事情:在Eclipse中从XML生成Java代码
- 编译代码生成器
- 运行代码生成器,将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();
}
}
这正是模型到文本(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>
给人命名包含三个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();
}
}
我不想将XML用作运行时数据格式 - 我正在使用它来简化我的源文件生成。 – 2012-08-14 13:02:38
JET是一个开发时工具,可以在Eclipse项目中生成代码,JSP,HTML,属性文件,Eclipse“点资源”等(可能在创建和配置这些项目之后)。该资源生成是由模型驱动的,通常是XML,但可以是任何格式,并且该模型在运行时完全不使用。所以JET对你来说确实是一个很好的方法。 在您的问题中发布示例类,我可以发布您可能用于生成该类的模板。 – 2012-08-14 15:38:00
我在我的问题中有几个例子。 – 2012-08-14 22:55:10
你可能想看看JaxB。
拉尔斯沃格尔做了一个简单的教程,如果你想快速浏览它。
JAXB Tutorial
另外这里是xml unmarshaling的基准测试。
XML unmarshalling benchmark in Java: JAXB vs STax vs Woodstox
我不想将XML用作运行时数据格式 - 我正在使用它来简化我的源文件生成。 – 2012-08-14 12:59:01
您要使用的是您的项目属性中的“Builders”选项。在这里,您可以设置您的项目,在编译其余项目之前,使用'ant'脚本编译和执行代码生成器(其他类型的构建器也可用)。
我认为这些文章更好的解释:
我可以得到downvote的原因吗? – 2012-08-17 12:54:02
你为什么不只是编写一个批处理文件/ shell脚本来完成这一切的吗?一行两个参数 - >完成!我这样问是因为我个人不知道你会如何(如果可能的话)在eclipse中做这件事,而且看起来你在这里很容易使用。 – thatidiotguy 2012-08-10 15:32:33
我希望它成为构建过程的一部分,以便如果我更改我的模板或XML,它将重新生成 – 2012-08-10 18:18:26
@thatidiotguy您可以将ant脚本作为项目属性的一部分集成到构建过程中,它位于“构建器”下。我不知道是否有批处理/ shell脚本支持,但我也没有看过。 – 2012-08-15 17:07:12