想法:在 Java 中嵌入数据/DSL 作为注释并使用 APT 生成 Java 代码
我有一个想法,我想由你来运行它以获得一些反馈。 请仔细阅读以下内容,让我知道您的想法,无论是积极的还是消极的。
我一直希望有一种方法可以将某些数据片段嵌入到 Java 代码中,而不必一直遵循 Java 的规则。 我最近听到了很多关于领域特定语言 (DSL) 的讨论,以及如果我们能够在日常工作中更多地利用它们,那就太好了。 我想我知道如何以相当优雅的方式做到这一点。
以下是我所知道的一些示例,这些示例在 Java 代码(和其他类 C 语言)中很难表示,我希望通过此方法来解决这些问题:
字符串数组的短字符串列表
String[] ar = { "Item1", "Item2", "Item3", "Item4" };
作为字符串数组的长字符串列表
String[] ar = { "The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.", };
作为 字符串作为多维字符串数组:
String[][] ar = { { "InvoiceID", "Date", "SubTotal", "Tax", "Total" },
{ "1", "1/2/2009", "300, "21", "321" },
{ "2", "1/4/2008", "100", "7", "107" },
{ "3", "1/6/2008", "200", "14", "214" } };
键值对列表
Map states = new HashMap();
states.add("FL", "Florida");
states.add("OH", "Ohio");
states.add("GA", "Georgia");
states.add("NY", "New York");
states.add("SC", "South Carolina");
HTML代码单字符串
String html = "<a href=\"www.somesite.com\">Some site</a>";
HTML文本块具有适当的文本格式
String html = "Hi, John,\r\n<br>\r\n<br>Thank you for writing to us. We do not currently carry that specific product.\r\n<br>\r\n<br>Regards,\r\n<br>";
我已经研究了以下描述的解决方案,我相信可以创建一个可用的库,它允许您优雅地实现这一点。 在 Java 5 和 6 中,有一个称为注释处理器工具 (APT) 的东西(与 Debian APT 不同)。 您创建自己的源代码处理器,该处理器将在编译代码时被调用,以便您有机会重写源代码。 重写代码后,它会像平常一样编译。
要使用 APT,必须执行以下操作: 1. 将此库的 jar 放在 ANT 类路径上。 2. 将此库的 jar 放在项目类路径中。 3. 调用 apt 任务而不是 javac,并添加 preprocessdir 参数来指定生成的文件必须放置的位置。
DSL 代码可以放置在变量后面的注释内,代码的结果将放置在该变量之后。 当处理器运行时,它可以在代码中查找下一个注释,提取代码,通过处理器运行它,生成代码并进行编译。
这里又是这个列表,这次它可能看起来像这样:
作为字符串数组的短字符串列表
@DslTextArray
String[] ar = null; /* Item1, Item2, Item3, Item4 */
作为字符串数组的长字符串列表
@DslMultilineTextArray
String[] ar = null;
/*
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
*/
作为多维字符串数组或 JTable 的字符串表:
@DslTextTable
String[][] ar = null;
/*
InvoiceID,Date,SubTotal,Tax,Total
1,1/2/2009,300,21,321
2,1/4/2008,100,7,107
3,1/6/2008,200,14,214
*/
键值对列表
@DslMap
Map states = null; /* FL=Florida, OH=Ohio, GA=Georgia, NY=New York, SC=South Carolina */
// Could also put each pair on a new line
HTML 代码单 具有适当文本格式的字符串
@DslText
String html = null; /* <a href="www.somesite.com">Some site</a> */
HTML 文本块
@DslText
String html = null;
/*
Hi, John,
Thank you for writing to us. We do not currently carry that specific product.
Regards,
Mike
*/
我可以想到此解决方案的一些要求/功能:
您必须声明变量来保存脚本将在 Java 源代码中生成的数据。 这使得源代码的其余部分可以了解结果数据,即使编译器不知道它来自哪里。
- 不得违反 Java 语言,以便 IDE 和 javac 不会显示错误。
- 使用您拥有的所有现有 Java 代码。 无需替换任何现有代码。 只需将这些片段添加到您喜欢的任何地方即可。
- 必须易于通过其他类型进行扩展。
- 稍后必须能够对 IDE 进行扩展,以允许源代码突出显示和自动完成。
- 翻译发生在编译时,因此必须生成有效的 Java 代码。
- 将列表、多行文本块(如 CSS、SQL)转换为 String 和 String[]
- 转换和编码 XML、HTML
- 重写代码时保留相同的行号。 不要添加任何行,这样调试和读取错误就不会变得痛苦。
- 在运行时运行用任何 BSF 语言编写的代码。 允许它将任何参数传递给脚本并将任何 Java 类或原语返回给 Java。
- 在编译时运行以任何 BSF 语言编写的代码以生成 Java 源代码。 类似于 Linux 上 M4 的使用方式。
- 稍后:允许您将多次调用的字符串结果链接在一起以构建长字符串。 有些可能是编译时的,有些可能是运行时的。
再次强调,我非常希望得到一些有关此问题的反馈。 这是一个愚蠢的想法吗? 已经有类似的东西了吗? 你会费心使用这样的东西还是我应该把它留给自己?
I had an idea and I wanted to run it by you to get some feedback. Please look the following over and let me know what you think, whether it's positive or negative.
I've always wished that there was a way to embed certain pieces of data in Java code without having to follow Java's rules all the time. I've heard a lot of talk about Domain Specific Languages lately (DSLs) and how it would be great if we could utilize them more on a daily basis. I think I have an idea of how to do this in a reasonably elegant way.
Here are some examples of things that I know of that are a pain to represent in Java code (and other C-like languages) that I want this to solve:
List of short strings as string array
String[] ar = { "Item1", "Item2", "Item3", "Item4" };
List of long strings as string array
String[] ar = { "The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.",
"The quick brown\n fox jumped over\n the lazy dog.", };
Table of strings as multi-dimensional string array:
String[][] ar = { { "InvoiceID", "Date", "SubTotal", "Tax", "Total" },
{ "1", "1/2/2009", "300, "21", "321" },
{ "2", "1/4/2008", "100", "7", "107" },
{ "3", "1/6/2008", "200", "14", "214" } };
List of key-value pairs
Map states = new HashMap();
states.add("FL", "Florida");
states.add("OH", "Ohio");
states.add("GA", "Georgia");
states.add("NY", "New York");
states.add("SC", "South Carolina");
HTML code single string
String html = "<a href=\"www.somesite.com\">Some site</a>";
HTML text block with decent text formatting
String html = "Hi, John,\r\n<br>\r\n<br>Thank you for writing to us. We do not currently carry that specific product.\r\n<br>\r\n<br>Regards,\r\n<br>";
I've investigated the following described solution a bit and I believe it's possible to create a usable library that would allow you to achieve this elegantly. In Java 5 and 6 there is something called the Annotation Processor Tool (APT) (not the same as Debian APT). You create your own source code processor, which will be called as the code is being compiled to give you the opportunity to rewrite the source code. After rewriting the code it is compiled as usual.
The following must be done to make use of APT:
1. Put this library's jar on the ANT classpath.
2. Put this library's jar on the project classpath.
3. Call the apt task instead of javac and add the preprocessdir parameter to specify where the generated files must be placed.
The DSL code can be placed inside a comment right after the variable where the result of the code will be placed. When the processor runs it can look forward in the code for the next comment, extract the code, run it through the processor, generate the code and do the compile.
Here is the list again, this time with what it could look like:
List of short strings as string array
@DslTextArray
String[] ar = null; /* Item1, Item2, Item3, Item4 */
List of long strings as string array
@DslMultilineTextArray
String[] ar = null;
/*
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
The quick brown
fox jumped over
the lazy dog.
*/
Table of strings as multi-dimensional string array or JTable:
@DslTextTable
String[][] ar = null;
/*
InvoiceID,Date,SubTotal,Tax,Total
1,1/2/2009,300,21,321
2,1/4/2008,100,7,107
3,1/6/2008,200,14,214
*/
List of key-value pairs
@DslMap
Map states = null; /* FL=Florida, OH=Ohio, GA=Georgia, NY=New York, SC=South Carolina */
// Could also put each pair on a new line
HTML code single string
@DslText
String html = null; /* <a href="www.somesite.com">Some site</a> */
HTML text block with decent text formatting
@DslText
String html = null;
/*
Hi, John,
Thank you for writing to us. We do not currently carry that specific product.
Regards,
Mike
*/
Some requirements/features I can think of for this solution:
You must declare the variable to hold the data that the script will generate in the Java source code. This allows the rest of the source code to know about the resulting data even though the compiler doesn't know where it's coming from.
- Must not violate the Java language so that the IDE and javac do not show errors.
- Work with all the existing Java code you have. No need to replace any existing code. Just add these snippets wherever you like.
- Must be easily extensible with additional types.
- Must be able to later make extensions to IDE's that allow for source-code highlighting and auto-completion.
- Translations occur at compile-time so valid Java code must be generated.
- Convert to String and String[] for things like lists, multi-line text blocks such as CSS, SQL
- Convert and encode XML, HTML
- When code is rewritten retain the same line numbers. Do not add any lines so that debugging and reading errors does not become a pain.
- Run code written in any BSF language at runtime. Allow it to pass any parameter to the script and return any Java class or primitive back to Java.
- Run code written in any BSF language at compile-time to generate Java source code. Similar to how M4 is used on Linux.
- Later: Allow you to chain together the String results from many calls to build a long string. Some if it may be compile-time, some of it run-time.
Again, I would really appreciate getting some feedback on this. Is this a stupid idea? Is there something like this out there already? Would you bother using something like this or should I just keep it to myself?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我现在将使用 google collections api,它是 guava 库 http://code.google 的一部分。 com/p/guava-libraries/ 它有很棒的列表和地图支持。 它支持您想要实现的构建类型
I would use the the google collections api now part of the guava libraries http://code.google.com/p/guava-libraries/ it has awesome list and map support. It support the kind of constructs your trying to achieve
这当然是可行的,但我必须说我不太喜欢它。
它使数据结构的初始化变得更加容易,
但是
我很少需要使用编译时常量来初始化这样的数据结构。 因此,类/java 文件旁边的单独文件会更有用
这对开发人员来说一点也不透明。 没有人期望评论会转化为数据。 实际上,如果遇到这样的评论,我可能会认为它评论了旧代码并立即将其删除
ATP 是一个强大而有趣的工具,但缺乏 IDE 集成。 因此,您必须始终使用 ANT 来构建和运行您的应用程序,这只是不如按 F11 或您的 IDE 为此目的提供的任何快捷方式那么好和快
所以基本上,您会以最小的代价在开发基础设施复杂性方面遭受巨大打击。提高打字速度。
这个想法仍然很有趣。 我实际上会欣赏一种变体,其中可以定义“DSL”类型的注释,允许以注释声明定义的任意语言将代码放入该注释中。 当然,这将是一个重大的语言变化,并且不会很快发生,而且可能根本不会发生。
This is feasible for sure, but I must say I don't like it to much.
It makes initialization of datastructures a little more easy,
BUT
I extremley rarely need to initialize datastructures like this with compile time constants. So a separate file nexht to the class/java file would be more usefull
This is not at all transparent for developers. Nobody expects comments to transform into data. Actually if a came across such a comment, I'd probably consider it commented old code and delete it immediately
ATP is a powerfull and interesting tool, yet the IDE integration is lacking. So you would have to build and run your application using ANT all the time, which is just not as nice and fast as hitten F11 or whatever shortcut your IDE offers for that purpose
So basically you take a huge hit in development infrastructure complexity for a minimal gain in typing speed.
Still the idea is interesting. I actually would apreciate a variation, where one could define a annotation of type "DSL" allowing to put code into that annotation in an arbitrary language defined by the annotation declaration. Of course that would be a major language change and won't happen anytime soon, and probably not at all.