- 浏览: 113944 次
- 性别:
- 来自: 成都
文章分类
最新评论
JDK6新特性一览
JDK6的新特性
JDK6的新特性之一_Desktop类和SystemTray类
JDK6的新特性之二_使用JAXB2来实现对象与XML之间的映射
JDK6的新特性之三_理解StAX
JDK6的新特性之四_使用Compiler API
JDK6的新特性之五_轻量级HttpServer
JDK6的新特性之七_用Console开发控制台程序
JDK6的新特性之八_嵌入式数据库Derby
JDK6的新特性之六_插入式注解处理API
JDK6的新特性之九_CommonAnnotations
JDK6的新特性之十_Web服务元数据
JDK6的新特性之十一_更简单强大的JAX-WS
JDK6的新特性之十三_JTable的排序和过滤
JDK6的新特性之十二_脚本语言支持
(1) JDK6的新特性之一_Desktop类和SystemTray类
在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray,前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱 发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托 盘程序。
Java代码
在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray,前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序.下面代码演示了Desktop和SystemTray的用法.
(2) JDK6的新特性之二_使用JAXB2来实现对象与XML之间的映射
JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。我们把对象与关系数据库之间的映射称为ORM, 其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping). 原来JAXB是Java EE的一部分,在JDK6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK6中自带的这个JAXB版本是2.0, 比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。实际上,在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。 闲话不多说了,下面用代码演示在JDK6中如何来用JAXB2
运行该程序,我们会得到一个person.xml的文件,如下:
Country:China
最后,想说一点,除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。
(3) JDK6的新特性之三_理解StAX
StAX(JSR 173)是JDK6.0中除了DOM和SAX之外的又一种处理XML文档的API
StAX的来历
在JAXP1.3(JSR 206)有两种处理XML文档的方法:DOM(Document Object Model)和SAX(Simple API for XML).由于JDK6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到StAX所以Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版本). JDK6里面JAXP的版本就是1.4.
StAX简介
StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件;DOM采用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。下面是这几种API的比较(转载自http://www.blogjava.net/hsith/archive/2006/06/29/55817.html)
XML Parser API Feature Summary Feature StAX SAX DOM TrAX
API Type Pull, streaming Push, streaming In memory tree XSLT Rule
Ease of Use High Medium High Medium
XPath Capability No No Yes Yes
CPU and Memory Efficiency Good Good Varies Varies
Forward Only Yes Yes No No
Read XML Yes Yes Yes Yes
Write XML Yes No Yes Yes
Create, Read, Update, Delete No No Yes No
StAX代码演示
下面代码演示了如何通过StAX读取xml文档和生成xml文档
运行上面程序后,控制台输出如下:
运行上面程序后,产生的output.xml文件如下:
现在我们可以用JDK6 的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用, 比如JSP Web Server,当我们手动修改JSP后,是不希望需要重启Web Server才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSP Web Server也是支持JSP热部署的,现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平台的。 下面代码演示了Compiler API的使用
程序运行后,会产生DynamicObject.java和DynamicObject.class两个文件,并在控制台输出
In the constructor of DynamicObject
(5) JDK6的新特性之五_轻量级HttpServer
JDK6提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法.下面代码演示了怎样创建自己的Http Server
运行程序后,在浏览器内输入http://localhost:8888/china浏览器输出
Happy New Year 2007!--China
(6) JDK6的新特性之六_插入式注解处理API
插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175),实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method, package, constructor, type, variable, enum, annotation等Java语言元素映射为Types和Elements(两者有什么区别?), 从而将Java语言的语义映射成为对象, 我们可以在javax.lang.model包下面可以看到这些类. 所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境. JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列. JSR 269主要被设计成为针对Tools或者容器的API. 举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法,如下所示:
这时我们就可以用JSR 269提供的API来处理测试类,根据Annotation提取出需要执行的测试方法.
另一个例子是如果我们出于某种原因需要自行开发一个符合Java EE 5.0的Application Server(当然不建议这样做),我们就必须处理Common Annotations(JSR 250),Web Services Metadata(JSR 181)等规范的Annotations,这时可以用JSR 269提供的API来处理这些Annotations. 在现在的开发工具里面,Eclipse 3.3承诺将支持JSR 269
下面我用代码演示如何来用JSR 269提供的API来处理Annotations和读取Java源文件的元数据(metadata)
编译以上代码,然后再创建下面的Testing对象,不要编译Testing对象,我在后面会编译它
下面我用以下命令编译Testing对象
本来想用JDK6.0的Compiler API来执行上面编译命令,可是好像现在Compiler API还不支持-processor参数,运行时总报以下错误
Exception in thread "main" java.lang.IllegalArgumentException: invalid flag: -processor PluggableAPT.MyAnnotationProcessor
调用Compiler API的代码是这样的
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects("Testing.java");
Set<String> options = new HashSet<String>();
options.add("-processor PluggableAPT.MyAnnotationProcessor");
compiler.getTask(null, fileManager, null, options, null, sourcefiles).call();
不知道这是不是Compiler API的一个bug.
(7) JDK6的新特性之七_用Console开发控制台程序
JDK6中提供了java.io.Console类专用来访问基于字符的控制台设备. 你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳. 但我们不总是能得到可用的Console, 一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用. 如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例. 下面代码演示了Console类的用法:
Console is unavailable
表示Console不可获得,那是因为JVM不是在命令行中被调用的或者输入输出被重定向了. 但是如果我们在命令行中运行上面程序(java ConsoleTest),程序能够获得Console实例,并执行如下:
Enter user:china
Enter passowrd:
User is:china
Password is:china
在这里可以看到输入密码时,控制台时不显示这些密码字符的,但是程序可以得到输入的密码字符串,这与Linux下面输入密码的情况是一样的
(8) JDK6的新特性之八_嵌入式数据库Derby
Derby并不是一个新的数据库产品,它是由IBM捐献给Apache的DB项目的一个纯Java数据库,JDK6.0里面带的这个Derby的版本是10.2.1.7,支持存储过程和触发器;有两种运行模式,一种是作为嵌入式数据库,另一种是作为网络数据库,前者的数据库服务器和客户端都在同一个JVM里面运行,后者允许数据库服务器端和客户端不在同一个JVM里面,而且允许这两者在不同的物理机器上.值得注意的是JDK6里面的这个Derby支持JDK6的新特性JDBC 4.0规范(JSR 221),现在我们如果要练习JDBC的用法,没有必要单独装一个数据库产品了,直接用Derby就行.安装完JDK6.0后,Derby会被安装到<JDK6_HOME>/db下面,在<JDK6_HOME>/db/demo/programs下面还有一些示例程序,演示了如何启动,连接Derby数据库以及JDBC API的使用.下面分两种情况演示一下如何用代码操作Derby数据库,一种是嵌入式数据库,一种是网络数据库.
一.嵌入式数据库
id=1;name=china
二.网络数据库
关于Derby的详细情况,请参考http://db.apache.org/derby
(9) JDK6的新特性之九_CommonAnnotations
Common annotations原本是Java EE 5.0(JSR 244)规范的一部分,现在SUN把它的一部分放到了Java SE 6.0中.随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,很多Java 技术(比如EJB,Web Services)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务), 如果这些技术为通用目的都单独定义了自己的Annotations,显然有点重复建设, 所以,为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免重复建设的同时,也保证Java SE和Java EE 各种技术的一致性.下面列举出Common Annotations 1.0里面的10个Annotations
注意:
1.RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上
2.标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的RolesAllowed,PermitAll,DenyAll
3.RunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles还没有加到Java SE 6.0上来
4.处理以上Annotations的工作是由Java EE容器来做, Java SE 6.0只是包含了上面表格的前五种Annotations的定义类,并没有包含处理这些Annotations的引擎,这个工作可以由Pluggable Annotation Processing API(JSR 269)来做
(10) JDK6的新特性之十_Web服务元数据
.Net的Web Services元数据
早在.Net Framework 1.0中,微软就用元数据功能(.net的attribute特性)来标注要暴露成Web Service的方法,下面是用C#演示的利用.net的元数据功能暴露Web Service方法的代码片断.
Java的Web Services元数据
Java 里的Web服务元数据跟微软的方案基本没有语义上的区别,自从JDK5添加了元数据功能(Annotation)之后,SUN几乎重构了整个J2EE体 系, 由于变化很大,干脆将名字也重构为Java EE, Java EE(当前版本为5.0)将元数据纳入很多规范当中,这其中就包括Web Services的相关规范, 加入元数据之后的Web Services服务器端编程模型就跟上面看到的C#片断差不多了, 这显然比以前的JAX-RPC编程模型简单(当然, Axis的编程模型也很简单).这里要谈的Web服务元数据(JSR 181)只是Java Web 服务规范中的一个,它跟Common Annotations, JAXB2, StAX, SAAJ和JAX-WS等共同构成Java EE 5的Web Services技术堆栈.
JSR-181的元数据清单
下面介绍JSR-181里面各个元数据的相关参数及用途
JSR-181元数据使用示例
1.将<JDK_HOME>/bin加入path环境变量
2.在命令行下切换当前目录到WSProvider的class文件所在的目录,运行下面命令
wsgen -cp . WebServices.WSProvider
在这个例子中会生成以下3个类的源代码文件及class文件
SayHi
SayHiResponse
PrintTime
3.执行如下代码发布WSProvider到http://localhost:8888/china/WSProvider,在这里可以执行WSProvider类的main方法就可以
Endpoint.publish("http://localhost:8888/china/WSProvider",new WSProvider());
4.在浏览器输入http://localhost:8888/china/WSProvider?wsdl就可以看到生成的WSDL文件,为了节省篇幅,这里就不把生成的WSDL文件贴上了,大家可以自己动手试试.
(11) JDK6的新特性之十一_更简单强大的JAX-WS
AX-WS2.0的来历
--------------------------------------------------------------------------------
JAX-WS(JSR-224) 是Java Architecture for XML Web Services的缩写,简单说就是一种用Java和XML开发Web Services应用程序的框架, 目前版本是2.0, 它是JAX-RPC 1.1的后续版本, J2EE 1.4带的就是JAX-RPC1.1, 而Java EE 5里面包括了JAX-WS 2.0,但为了向后兼容,仍然支持JAX-RPC. 现在,SUN又把JAX-WS直接放到了Java SE 6里面,由于JAX-WS会用到Common Annotation(JSR 250),Java Web Services Metadata(JSR 181), JAXB2(JSR 222), StAX(JSR 173), 所以SUN也必须把后几个原属于Java EE范畴的Components下放到Java SE, 现在我们可以清楚地理解了为什么Sun要把这些看似跟Java SE没有关系的Components放进来,终极目的就是要在Java SE里面支持Web Services.
JAX-WS2.0的架构
--------------------------------------------------------------------------------
JAX-WS不是一个孤立的框架,它依赖于众多其他的规范,本质上它由以下几部分组成
JAX-WS2.0的编程模型
--------------------------------------------------------------------------------
现在用JAX-WS2.0来编写Web Services非常简单,不像JAX-RPC,JAX-WS可以把任意POJO暴露为Web Services,服务类不需要实现接口,服务方法也没有必要抛出RMI异常.下面介绍在JDK6环境下用JAX-WS2.0开发和测试Web Services的步骤
1.编写服务类,并用Web Services Metadata(JSR-181)标注这个服务类,我用我的另一篇BlogJDK6的新特性之十:Web服务元数据中的WSProvider类作为服务类的例子,在此我重复贴一下WSProvider类的源代码:
3.用wsimport为服务消费者(也就是服务的客户端)生成必要的帮助类,命令如下:
hi,china
服务端控制台输出服务器当前系统时间
(12) JDK6的新特性之十二_脚本语言支持
--------------------------------------------------------------------------------
JDK6增加了对脚本语言的支持(JSR 223),原理上是将脚本语言编译成bytecode,这样脚本语言也能享用Java平台的诸多优势,包括可移植性,安全等,另外,由于现在是编译成bytecode后再执行,所以比原来边解释边执行效率要高很多。加入对脚本语言的支持后,对Java语言也提供了以下好处。
Scripting API
--------------------------------------------------------------------------------
Scripting API是用于在Java里面编写脚本语言程序的API, 在Javax.script中可以找到Scripting API,我们就是用这个API来编写JavaScript程序,这个包里面有一个ScriptEngineManager类,它是使用Scripting API的入口,ScriptEngineManager可以通过jar服务发现(service discovery)机制寻找合适的脚本引擎类(ScriptEngine),使用Scripting API的最简单方式只需下面三步
1、创建一个ScriptEngineManager对象
2、通过ScriptEngineManager获得ScriptEngine对象
3、用ScriptEngine的eval方法执行脚本
下面是一个Hello World程序
--------------------------------------------------------------------------------
SUN提供的JDK6中有一个命令行工具??jrunscript,你可以在<JDK6_Home>/bin下面找到这个工具,jrunscript是一个脚本语言的解释程序,它独立于脚本语言,但默认是用JavaScript,我们可以用jrunscript来测试自己写的脚本语言是否正确,下面是一个在命令行运行jrunscript的简单例子
(13) JDK6的新特性之十三_JTable的排序和过滤
原来的JTable基本上是只能显示数据,在JDK6新增了对JTable的排序和过滤功能,下面代码演示了这两个功能
JDK6的新特性之一_Desktop类和SystemTray类
JDK6的新特性之二_使用JAXB2来实现对象与XML之间的映射
JDK6的新特性之三_理解StAX
JDK6的新特性之四_使用Compiler API
JDK6的新特性之五_轻量级HttpServer
JDK6的新特性之七_用Console开发控制台程序
JDK6的新特性之八_嵌入式数据库Derby
JDK6的新特性之六_插入式注解处理API
JDK6的新特性之九_CommonAnnotations
JDK6的新特性之十_Web服务元数据
JDK6的新特性之十一_更简单强大的JAX-WS
JDK6的新特性之十三_JTable的排序和过滤
JDK6的新特性之十二_脚本语言支持
(1) JDK6的新特性之一_Desktop类和SystemTray类
在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray,前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱 发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托 盘程序。
Java代码
在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray,前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定的邮箱发邮件,用默认应用程序打开或编辑文件(比如,用记事本打开以txt为后缀名的文件),用系统默认的打印机打印文档;后者可以用来在系统托盘区创建一个托盘程序.下面代码演示了Desktop和SystemTray的用法.
/**
*
*/
importjava.awt.Desktop;
importjava.awt.SystemTray;
importjava.awt.TrayIcon;
importjava.awt.Toolkit;
importjava.awt.Image;
importjava.awt.PopupMenu;
importjava.awt.Menu;
importjava.awt.MenuItem;
importjava.awt.AWTException;
importjava.io.File;
importjava.io.IOException;
importjava.net.URI;
importjava.net.URISyntaxException;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
publicclassDesktopTray {
privatestaticDesktop desktop;
privatestaticSystemTray st;
privatestaticPopupMenu pm;
publicstaticvoidmain(String[] args) {
if(Desktop.isDesktopSupported()){//判断当前平台是否支持Desktop类
desktop=Desktop.getDesktop();
}
if(SystemTray.isSupported()){//判断当前平台是否支持系统托盘
st=SystemTray.getSystemTray();
Image image=Toolkit.getDefaultToolkit().getImage("netbeans.png");//定义托盘图标的图片
createPopupMenu();
TrayIcon ti=newTrayIcon(image,"Desktop Demo Tray", pm);
try{
st.add(ti);
}catch(AWTException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoidsendMail(String mail){
if(desktop!=null&&desktop.isSupported(Desktop.Action.MAIL)){
try{
desktop.mail(newURI(mail));
}catch(IOException ex) {
ex.printStackTrace();
}catch(URISyntaxException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoid openBrowser(String url){
if(desktop!=null&&desktop.isSupported(Desktop.Action.BROWSE)){
try{
desktop.browse(newURI(url));
}catch(IOException ex) {
ex.printStackTrace();
}catch(URISyntaxException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoid edit(){
if(desktop!=null&&desktop.isSupported(Desktop.Action.EDIT)){
try{
File txtFile=newFile("test.txt");
if(!txtFile.exists()){
txtFile.createNewFile();
}
desktop.edit(txtFile);
}catch(IOException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoidcreatePopupMenu(){
pm=newPopupMenu();
MenuItem openBrowser=newMenuItem("Open My Blog");
openBrowser.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
openBrowser("http://blog.csdn.net/china");
}
});
MenuItem sendMail=newMenuItem("Send Mail to me");
sendMail.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
sendMail("mailto:china@yahoo.com.cn");
}
});
MenuItem edit=newMenuItem("Edit Text File");
sendMail.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
edit();
}
});
MenuItem exitMenu=newMenuItem("&Exit");
exitMenu.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
System.exit(0);
}
});
pm.add(openBrowser);
pm.add(sendMail);
pm.add(edit);
pm.addSeparator();
pm.add(exitMenu);
}
}
如果在Windows中运行该程序,可以看到在系统托盘区有一个图标,右击该图标会弹出一个菜单,点击Open My Blog会打开IE,并浏览"http://blog.csdn.net/china";点击Send Mail to me会打开Outlook Express给我发邮件;点击Edit Text
File会打开记事本编辑在程序中创建的文件test.txt*
*/
importjava.awt.Desktop;
importjava.awt.SystemTray;
importjava.awt.TrayIcon;
importjava.awt.Toolkit;
importjava.awt.Image;
importjava.awt.PopupMenu;
importjava.awt.Menu;
importjava.awt.MenuItem;
importjava.awt.AWTException;
importjava.io.File;
importjava.io.IOException;
importjava.net.URI;
importjava.net.URISyntaxException;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
publicclassDesktopTray {
privatestaticDesktop desktop;
privatestaticSystemTray st;
privatestaticPopupMenu pm;
publicstaticvoidmain(String[] args) {
if(Desktop.isDesktopSupported()){//判断当前平台是否支持Desktop类
desktop=Desktop.getDesktop();
}
if(SystemTray.isSupported()){//判断当前平台是否支持系统托盘
st=SystemTray.getSystemTray();
Image image=Toolkit.getDefaultToolkit().getImage("netbeans.png");//定义托盘图标的图片
createPopupMenu();
TrayIcon ti=newTrayIcon(image,"Desktop Demo Tray", pm);
try{
st.add(ti);
}catch(AWTException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoidsendMail(String mail){
if(desktop!=null&&desktop.isSupported(Desktop.Action.MAIL)){
try{
desktop.mail(newURI(mail));
}catch(IOException ex) {
ex.printStackTrace();
}catch(URISyntaxException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoid openBrowser(String url){
if(desktop!=null&&desktop.isSupported(Desktop.Action.BROWSE)){
try{
desktop.browse(newURI(url));
}catch(IOException ex) {
ex.printStackTrace();
}catch(URISyntaxException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoid edit(){
if(desktop!=null&&desktop.isSupported(Desktop.Action.EDIT)){
try{
File txtFile=newFile("test.txt");
if(!txtFile.exists()){
txtFile.createNewFile();
}
desktop.edit(txtFile);
}catch(IOException ex) {
ex.printStackTrace();
}
}
}
publicstaticvoidcreatePopupMenu(){
pm=newPopupMenu();
MenuItem openBrowser=newMenuItem("Open My Blog");
openBrowser.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
openBrowser("http://blog.csdn.net/china");
}
});
MenuItem sendMail=newMenuItem("Send Mail to me");
sendMail.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
sendMail("mailto:china@yahoo.com.cn");
}
});
MenuItem edit=newMenuItem("Edit Text File");
sendMail.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
edit();
}
});
MenuItem exitMenu=newMenuItem("&Exit");
exitMenu.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
System.exit(0);
}
});
pm.add(openBrowser);
pm.add(sendMail);
pm.add(edit);
pm.addSeparator();
pm.add(exitMenu);
}
}
(2) JDK6的新特性之二_使用JAXB2来实现对象与XML之间的映射
JAXB是Java Architecture for XML Binding的缩写,可以将一个Java对象转变成为XML格式,反之亦然。我们把对象与关系数据库之间的映射称为ORM, 其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping). 原来JAXB是Java EE的一部分,在JDK6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK6中自带的这个JAXB版本是2.0, 比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。实际上,在Java EE 5.0中,EJB和Web Services也通过Annotation来简化开发工作。另外,JAXB2在底层是用StAX(JSR 173)来处理XML文档。 闲话不多说了,下面用代码演示在JDK6中如何来用JAXB2
publicclassJAXB2Tester {
publicstaticvoidmain(String[] args)throwsJAXBException,IOException {
JAXBContext context=JAXBContext.newInstance(Person.class);
//下面代码演示将对象转变为xml
Marshaller m=context.createMarshaller();
Address address=newAddress("China","Beijing","Beijing","ShangDi West","100080");
Person p=newPerson(Calendar.getInstance(),"JAXB2",address,Gender.MALE,"SW");
FileWriter fw=newFileWriter("person.xml");
m.marshal(p,fw);
//下面代码演示将上面生成的xml转换为对象
FileReader fr=newFileReader("person.xml");
Unmarshaller um=context.createUnmarshaller();
Person p2=(Person)um.unmarshal(fr);
System.out.println("Country:"+p2.getAddress().getCountry());
}
}
@XmlRootElement//表示person是一个根元素
classPerson {
@XmlElement
Calendar birthDay;//birthday将作为person的子元素
@XmlAttribute
String name;//name将作为person的的一个属性
publicAddress getAddress() {
returnaddress;
}
@XmlElement
Address address;//address将作为person的子元素
@XmlElement
Gender gender;//gender将作为person的子元素
@XmlElement
String job;//job将作为person的子元素
publicPerson(){
}
publicPerson(Calendar birthDay, String name, Address address, Gender gender, String job) {
this.birthDay=birthDay;
this.name=name;
this.address=address;
this.gender=gender;
this.job=job;
}
}
enum Gender{
MALE(true),
FEMALE (false);
privatebooleanvalue;
Gender(boolean_value){
value=_value;
}
}
classAddress {
@XmlAttribute
String country;
@XmlElement
String state;
@XmlElement
String city;
@XmlElement
String street;
String zipcode;//由于没有添加@XmlElement,所以该元素不会出现在输出的xml中
publicAddress() {
}
publicAddress(String country, String state, String city, String street, String zipcode) {
this.country=country;
this.state=state;
this.city=city;
this.street=street;
this.zipcode=zipcode;
}
publicString getCountry() {
returncountry;
}
}
publicstaticvoidmain(String[] args)throwsJAXBException,IOException {
JAXBContext context=JAXBContext.newInstance(Person.class);
//下面代码演示将对象转变为xml
Marshaller m=context.createMarshaller();
Address address=newAddress("China","Beijing","Beijing","ShangDi West","100080");
Person p=newPerson(Calendar.getInstance(),"JAXB2",address,Gender.MALE,"SW");
FileWriter fw=newFileWriter("person.xml");
m.marshal(p,fw);
//下面代码演示将上面生成的xml转换为对象
FileReader fr=newFileReader("person.xml");
Unmarshaller um=context.createUnmarshaller();
Person p2=(Person)um.unmarshal(fr);
System.out.println("Country:"+p2.getAddress().getCountry());
}
}
@XmlRootElement//表示person是一个根元素
classPerson {
@XmlElement
Calendar birthDay;//birthday将作为person的子元素
@XmlAttribute
String name;//name将作为person的的一个属性
publicAddress getAddress() {
returnaddress;
}
@XmlElement
Address address;//address将作为person的子元素
@XmlElement
Gender gender;//gender将作为person的子元素
@XmlElement
String job;//job将作为person的子元素
publicPerson(){
}
publicPerson(Calendar birthDay, String name, Address address, Gender gender, String job) {
this.birthDay=birthDay;
this.name=name;
this.address=address;
this.gender=gender;
this.job=job;
}
}
enum Gender{
MALE(true),
FEMALE (false);
privatebooleanvalue;
Gender(boolean_value){
value=_value;
}
}
classAddress {
@XmlAttribute
String country;
@XmlElement
String state;
@XmlElement
String city;
@XmlElement
String street;
String zipcode;//由于没有添加@XmlElement,所以该元素不会出现在输出的xml中
publicAddress() {
}
publicAddress(String country, String state, String city, String street, String zipcode) {
this.country=country;
this.state=state;
this.city=city;
this.street=street;
this.zipcode=zipcode;
}
publicString getCountry() {
returncountry;
}
}
运行该程序,我们会得到一个person.xml的文件,如下:
<?xml version="1.0"encoding="UTF-8"standalone="yes"?>
<personname="JAXB2">
<birthDay>2006-12-28T08:49:27.203+00:00</birthDay>
<addresscountry="China">
<state>Beijing</state>
<city>Beijing</city>
<street>ShangDi West</street>
</address>
<gender>MALE</gender>
<job>SW</job>
</person>
控制台会输出<personname="JAXB2">
<birthDay>2006-12-28T08:49:27.203+00:00</birthDay>
<addresscountry="China">
<state>Beijing</state>
<city>Beijing</city>
<street>ShangDi West</street>
</address>
<gender>MALE</gender>
<job>SW</job>
</person>
Country:China
最后,想说一点,除了JAXB之外,我们还可以通过XMLBeans和Castor等来实现同样的功能。
(3) JDK6的新特性之三_理解StAX
StAX(JSR 173)是JDK6.0中除了DOM和SAX之外的又一种处理XML文档的API
StAX的来历
在JAXP1.3(JSR 206)有两种处理XML文档的方法:DOM(Document Object Model)和SAX(Simple API for XML).由于JDK6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到StAX所以Sun决定把StAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3的维护版本). JDK6里面JAXP的版本就是1.4.
StAX简介
StAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API.StAX通过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每一个解析事件,解析事件可以看做是程序拉出来的,也就是程序促使解析器产生一个解析事件然后处理该事件,之后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;SAX也是基于事件处理xml文档,但却是用推模式解析,解析器解析完整个xml文档后,才产生解析事件,然后推给程序去处理这些事件;DOM采用的方式是将整个xml文档映射到一颗内存树,这样就可以很容易地得到父节点和子结点以及兄弟节点的数据,但如果文档很大,将会严重影响性能。下面是这几种API的比较(转载自http://www.blogjava.net/hsith/archive/2006/06/29/55817.html)
XML Parser API Feature Summary Feature StAX SAX DOM TrAX
API Type Pull, streaming Push, streaming In memory tree XSLT Rule
Ease of Use High Medium High Medium
XPath Capability No No Yes Yes
CPU and Memory Efficiency Good Good Varies Varies
Forward Only Yes Yes No No
Read XML Yes Yes Yes Yes
Write XML Yes No Yes Yes
Create, Read, Update, Delete No No Yes No
StAX代码演示
下面代码演示了如何通过StAX读取xml文档和生成xml文档
publicclassStaxTester {
publicstaticvoidmain(String[] args)throwsXMLStreamException, FileNotFoundException {
readXMLByStAX();//用XMLEventReader解析xml文档
writeXMLByStAX();//用XMLStreamWriter写xml文档
}
privatestaticvoidreadXMLByStAX()throwsXMLStreamException, FileNotFoundException {
XMLInputFactory xmlif=XMLInputFactory.newInstance();
XMLEventReader xmler=xmlif.createXMLEventReader(StaxTester.class.getResourceAsStream("test.xml"));
XMLEvent event;
StringBuffer parsingResult=newStringBuffer();
while(xmler.hasNext()) {
event=xmler.nextEvent();
if(event.isStartElement()) {//如果解析的是起始标记
StartElement se=event.asStartElement();
parsingResult.append("<");
parsingResult.append(se.getName());
if(se.getName().getLocalPart().equals("catalog")) {
parsingResult.append(" id=\"");
parsingResult.append(se.getAttributeByName(newQName("id")).getValue());
parsingResult.append("\"");
}
parsingResult.append(">");
}elseif(event.isCharacters()) {//如果解析的是文本内容
parsingResult.append(event.asCharacters().getData());
}elseif(event.isEndElement()){//如果解析的是结束标记
parsingResult.append("</");
parsingResult.append(event.asEndElement().getName());
parsingResult.append(">");
}
}
System.out.println(parsingResult);
}
privatestaticvoidwriteXMLByStAX()throwsXMLStreamException, FileNotFoundException {
XMLOutputFactory xmlof=XMLOutputFactory.newInstance();
XMLStreamWriter xmlw=xmlof.createXMLStreamWriter(newFileOutputStream("output.xml"));
// 写入默认的 XML 声明到xml文档
xmlw.writeStartDocument();
xmlw.writeCharacters("\n");
// 写入注释到xml文档
xmlw.writeComment("testing comment");
xmlw.writeCharacters("\n");
// 写入一个catalogs根元素
xmlw.writeStartElement("catalogs");
xmlw.writeNamespace("myNS","http://blog.csdn.net/China");
xmlw.writeAttribute("owner","China");
xmlw.writeCharacters("\n");
// 写入子元素catalog
xmlw.writeStartElement("http://blog.csdn.net/China","catalog");
xmlw.writeAttribute("id","007");
xmlw.writeCharacters("Apparel");
// 写入catalog元素的结束标签
xmlw.writeEndElement();
// 写入catalogs元素的结束标签
xmlw.writeEndElement();
// 结束 XML 文档
xmlw.writeEndDocument();
xmlw.close();
}
}
test.xml文件内容如下:publicstaticvoidmain(String[] args)throwsXMLStreamException, FileNotFoundException {
readXMLByStAX();//用XMLEventReader解析xml文档
writeXMLByStAX();//用XMLStreamWriter写xml文档
}
privatestaticvoidreadXMLByStAX()throwsXMLStreamException, FileNotFoundException {
XMLInputFactory xmlif=XMLInputFactory.newInstance();
XMLEventReader xmler=xmlif.createXMLEventReader(StaxTester.class.getResourceAsStream("test.xml"));
XMLEvent event;
StringBuffer parsingResult=newStringBuffer();
while(xmler.hasNext()) {
event=xmler.nextEvent();
if(event.isStartElement()) {//如果解析的是起始标记
StartElement se=event.asStartElement();
parsingResult.append("<");
parsingResult.append(se.getName());
if(se.getName().getLocalPart().equals("catalog")) {
parsingResult.append(" id=\"");
parsingResult.append(se.getAttributeByName(newQName("id")).getValue());
parsingResult.append("\"");
}
parsingResult.append(">");
}elseif(event.isCharacters()) {//如果解析的是文本内容
parsingResult.append(event.asCharacters().getData());
}elseif(event.isEndElement()){//如果解析的是结束标记
parsingResult.append("</");
parsingResult.append(event.asEndElement().getName());
parsingResult.append(">");
}
}
System.out.println(parsingResult);
}
privatestaticvoidwriteXMLByStAX()throwsXMLStreamException, FileNotFoundException {
XMLOutputFactory xmlof=XMLOutputFactory.newInstance();
XMLStreamWriter xmlw=xmlof.createXMLStreamWriter(newFileOutputStream("output.xml"));
// 写入默认的 XML 声明到xml文档
xmlw.writeStartDocument();
xmlw.writeCharacters("\n");
// 写入注释到xml文档
xmlw.writeComment("testing comment");
xmlw.writeCharacters("\n");
// 写入一个catalogs根元素
xmlw.writeStartElement("catalogs");
xmlw.writeNamespace("myNS","http://blog.csdn.net/China");
xmlw.writeAttribute("owner","China");
xmlw.writeCharacters("\n");
// 写入子元素catalog
xmlw.writeStartElement("http://blog.csdn.net/China","catalog");
xmlw.writeAttribute("id","007");
xmlw.writeCharacters("Apparel");
// 写入catalog元素的结束标签
xmlw.writeEndElement();
// 写入catalogs元素的结束标签
xmlw.writeEndElement();
// 结束 XML 文档
xmlw.writeEndDocument();
xmlw.close();
}
}
<?xml version="1.0"encoding="UTF-8"?>
<catalogs>
<catalogid="001">Book</catalog>
<catalogid="002">Video</catalog>
</catalogs>
<catalogs>
<catalogid="001">Book</catalog>
<catalogid="002">Video</catalog>
</catalogs>
运行上面程序后,控制台输出如下:
<catalogs>
<catalogid="001">Book</catalog>
<catalogid="002">Video</catalog>
</catalogs>
<catalogid="001">Book</catalog>
<catalogid="002">Video</catalog>
</catalogs>
运行上面程序后,产生的output.xml文件如下:
<?xml version="1.0"?>
<!-- testing comment-->
<catalogs xmlns:myNS="http://blog.csdn.net/China"owner="China">
<myNS:catalogid="007">Apparel</myNS:catalog>
</catalogs>
(4) JDK6的新特性之四_使用Compiler API<!-- testing comment-->
<catalogs xmlns:myNS="http://blog.csdn.net/China"owner="China">
<myNS:catalogid="007">Apparel</myNS:catalog>
</catalogs>
现在我们可以用JDK6 的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就可以实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些需要用到动态编译的应用程序相当有用, 比如JSP Web Server,当我们手动修改JSP后,是不希望需要重启Web Server才可以看到效果的,这时候我们就可以用Compiler API来实现动态编译JSP文件,当然,现在的JSP Web Server也是支持JSP热部署的,现在的JSP Web Server通过在运行期间通过Runtime.exec或ProcessBuilder来调用javac来编译代码,这种方式需要我们产生另一个进程去做编译工作,不够优雅而且容易使代码依赖与特定的操作系统;Compiler API通过一套易用的标准的API提供了更加丰富的方式去做动态编译,而且是跨平台的。 下面代码演示了Compiler API的使用
publicclassCompilerAPITester {
privatestaticString JAVA_SOURCE_FILE="DynamicObject.java";
privatestaticString JAVA_CLASS_FILE="DynamicObject.class";
privatestaticString JAVA_CLASS_NAME="DynamicObject";
publicstaticvoidmain(String[] args) {
JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager=compiler.getStandardFileManager(null, null, null);
generateJavaClass();
try{
//将产生的类文件拷贝到程序的ClassPath下面,下面这一行代码是特定于Windows+IntelliJ IDEA 6.0项目,不具有移植性
Runtime.getRuntime().exec("cmd /c copy "+JAVA_CLASS_FILE+" classes\\production\\JDK6Features");
Iterable<?extendsJavaFileObject>sourcefiles=fileManager.getJavaFileObjects(JAVA_SOURCE_FILE);
compiler.getTask(null, fileManager, null, null, null, sourcefiles).call();
fileManager.close();
Class.forName(JAVA_CLASS_NAME).newInstance();//创建动态编译得到的DynamicObject类的实例
}catch(Exception ex) {
ex.printStackTrace();
}
}
publicstaticvoidgenerateJavaClass(){
try{
FileWriter fw=newFileWriter(JAVA_SOURCE_FILE);
BufferedWriter bw=newBufferedWriter(fw);
bw.write("public class "+JAVA_CLASS_NAME+"{");
bw.newLine();
bw.write("public "+JAVA_CLASS_NAME+"(){System.out.println(\"In the constructor of DynamicObject\");}}");
bw.flush();
bw.close();
}catch(IOException ex) {
ex.printStackTrace();
}
}
}
privatestaticString JAVA_SOURCE_FILE="DynamicObject.java";
privatestaticString JAVA_CLASS_FILE="DynamicObject.class";
privatestaticString JAVA_CLASS_NAME="DynamicObject";
publicstaticvoidmain(String[] args) {
JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager=compiler.getStandardFileManager(null, null, null);
generateJavaClass();
try{
//将产生的类文件拷贝到程序的ClassPath下面,下面这一行代码是特定于Windows+IntelliJ IDEA 6.0项目,不具有移植性
Runtime.getRuntime().exec("cmd /c copy "+JAVA_CLASS_FILE+" classes\\production\\JDK6Features");
Iterable<?extendsJavaFileObject>sourcefiles=fileManager.getJavaFileObjects(JAVA_SOURCE_FILE);
compiler.getTask(null, fileManager, null, null, null, sourcefiles).call();
fileManager.close();
Class.forName(JAVA_CLASS_NAME).newInstance();//创建动态编译得到的DynamicObject类的实例
}catch(Exception ex) {
ex.printStackTrace();
}
}
publicstaticvoidgenerateJavaClass(){
try{
FileWriter fw=newFileWriter(JAVA_SOURCE_FILE);
BufferedWriter bw=newBufferedWriter(fw);
bw.write("public class "+JAVA_CLASS_NAME+"{");
bw.newLine();
bw.write("public "+JAVA_CLASS_NAME+"(){System.out.println(\"In the constructor of DynamicObject\");}}");
bw.flush();
bw.close();
}catch(IOException ex) {
ex.printStackTrace();
}
}
}
程序运行后,会产生DynamicObject.java和DynamicObject.class两个文件,并在控制台输出
In the constructor of DynamicObject
(5) JDK6的新特性之五_轻量级HttpServer
JDK6提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,程序员必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法.下面代码演示了怎样创建自己的Http Server
/**
* Created by IntelliJ IDEA.
* User: China
* Date: Dec 30, 2006
*/
publicclassHTTPServerAPITester {
publicstaticvoidmain(String[] args) {
try{
HttpServer hs=HttpServer.create(newInetSocketAddress(8888),0);//设置HttpServer的端口为8888
hs.createContext("/china",newMyHandler());//用MyHandler类内处理到/china的请求
hs.setExecutor(null);// creates a default executor
hs.start();
}catch(IOException e) {
e.printStackTrace();
}
}
}
classMyHandlerimplementsHttpHandler {
publicvoidhandle(HttpExchange t)throwsIOException {
InputStream is=t.getRequestBody();
String response="<h3>Happy New Year 2009!--China</h3>";
t.sendResponseHeaders(200, response.length());
OutputStream os=t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
* Created by IntelliJ IDEA.
* User: China
* Date: Dec 30, 2006
*/
publicclassHTTPServerAPITester {
publicstaticvoidmain(String[] args) {
try{
HttpServer hs=HttpServer.create(newInetSocketAddress(8888),0);//设置HttpServer的端口为8888
hs.createContext("/china",newMyHandler());//用MyHandler类内处理到/china的请求
hs.setExecutor(null);// creates a default executor
hs.start();
}catch(IOException e) {
e.printStackTrace();
}
}
}
classMyHandlerimplementsHttpHandler {
publicvoidhandle(HttpExchange t)throwsIOException {
InputStream is=t.getRequestBody();
String response="<h3>Happy New Year 2009!--China</h3>";
t.sendResponseHeaders(200, response.length());
OutputStream os=t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
运行程序后,在浏览器内输入http://localhost:8888/china浏览器输出
Happy New Year 2007!--China
(6) JDK6的新特性之六_插入式注解处理API
插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175),实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method, package, constructor, type, variable, enum, annotation等Java语言元素映射为Types和Elements(两者有什么区别?), 从而将Java语言的语义映射成为对象, 我们可以在javax.lang.model包下面可以看到这些类. 所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境. JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列. JSR 269主要被设计成为针对Tools或者容器的API. 举个例子,我们想建立一套基于Annotation的单元测试框架(如TestNG),在测试类里面用Annotation来标识测试期间需要执行的测试方法,如下所示:
@TestMethod
publicvoidtestCheckName(){
//do something here
}
publicvoidtestCheckName(){
//do something here
}
这时我们就可以用JSR 269提供的API来处理测试类,根据Annotation提取出需要执行的测试方法.
另一个例子是如果我们出于某种原因需要自行开发一个符合Java EE 5.0的Application Server(当然不建议这样做),我们就必须处理Common Annotations(JSR 250),Web Services Metadata(JSR 181)等规范的Annotations,这时可以用JSR 269提供的API来处理这些Annotations. 在现在的开发工具里面,Eclipse 3.3承诺将支持JSR 269
下面我用代码演示如何来用JSR 269提供的API来处理Annotations和读取Java源文件的元数据(metadata)
/**
* Created by IntelliJ IDEA.
* User: China
* Date: Dec 31, 2006
*/
@SupportedAnnotationTypes("PluggableAPT.ToBeTested")//可以用"*"表示支持所有Annotations
@SupportedSourceVersion(SourceVersion.RELEASE_6)
publicclassMyAnnotationProcessorextendsAbstractProcessor {
privatevoidnote(String msg) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
}
publicbooleanprocess(Set<?extendsTypeElement>annotations, RoundEnvironment roundEnv) {
//annotations的值是通过@SupportedAnnotationTypes声明的且目标源代码拥有的所有Annotations
for(TypeElement te:annotations){
note("annotation:"+te.toString());
}
Set<?extendsElement>elements=roundEnv.getRootElements();//获取源代码的映射对象
for(Element e:elements){
//获取源代码对象的成员
List<?extendsElement>enclosedElems=e.getEnclosedElements();
//留下方法成员,过滤掉其他成员
List<?extendsExecutableElement>ees=ElementFilter.methodsIn(enclosedElems);
for(ExecutableElement ee:ees){
note("--ExecutableElement name is "+ee.getSimpleName());
List<?extendsAnnotationMirror>as=ee.getAnnotationMirrors();//获取方法的Annotations
note("--as="+as);
for(AnnotationMirror am:as){
//获取Annotation的值
Map<?extendsExecutableElement,?extendsAnnotationValue>map=am.getElementValues();
Set<?extendsExecutableElement>ks=map.keySet();
for(ExecutableElement k:ks){//打印Annotation的每个值
AnnotationValue av=map.get(k);
note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue());
}
}
}
}
returnfalse;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interfaceToBeTested{
String owner()default"China";
String group();
}
* Created by IntelliJ IDEA.
* User: China
* Date: Dec 31, 2006
*/
@SupportedAnnotationTypes("PluggableAPT.ToBeTested")//可以用"*"表示支持所有Annotations
@SupportedSourceVersion(SourceVersion.RELEASE_6)
publicclassMyAnnotationProcessorextendsAbstractProcessor {
privatevoidnote(String msg) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
}
publicbooleanprocess(Set<?extendsTypeElement>annotations, RoundEnvironment roundEnv) {
//annotations的值是通过@SupportedAnnotationTypes声明的且目标源代码拥有的所有Annotations
for(TypeElement te:annotations){
note("annotation:"+te.toString());
}
Set<?extendsElement>elements=roundEnv.getRootElements();//获取源代码的映射对象
for(Element e:elements){
//获取源代码对象的成员
List<?extendsElement>enclosedElems=e.getEnclosedElements();
//留下方法成员,过滤掉其他成员
List<?extendsExecutableElement>ees=ElementFilter.methodsIn(enclosedElems);
for(ExecutableElement ee:ees){
note("--ExecutableElement name is "+ee.getSimpleName());
List<?extendsAnnotationMirror>as=ee.getAnnotationMirrors();//获取方法的Annotations
note("--as="+as);
for(AnnotationMirror am:as){
//获取Annotation的值
Map<?extendsExecutableElement,?extendsAnnotationValue>map=am.getElementValues();
Set<?extendsExecutableElement>ks=map.keySet();
for(ExecutableElement k:ks){//打印Annotation的每个值
AnnotationValue av=map.get(k);
note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue());
}
}
}
}
returnfalse;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interfaceToBeTested{
String owner()default"China";
String group();
}
编译以上代码,然后再创建下面的Testing对象,不要编译Testing对象,我在后面会编译它
publicclassTesting{
@ToBeTested(group="A")
publicvoidm1(){
}
@ToBeTested(group="B",owner="QQ")
publicvoidm2(){
}
@PostConstruct//Common Annotation里面的一个Annotation
publicvoidm3(){
}
}
@ToBeTested(group="A")
publicvoidm1(){
}
@ToBeTested(group="B",owner="QQ")
publicvoidm2(){
}
@PostConstruct//Common Annotation里面的一个Annotation
publicvoidm3(){
}
}
下面我用以下命令编译Testing对象
javac-XprintRounds-processor PluggableAPT.MyAnnotationProcessor Testing.java
-XprintRounds表示打印round的次数,运行上面命令后在控制台会看到如下输出:
Round1:
input files:{PluggableAPT.Testing}
annotations:[PluggableAPT.ToBeTested, javax.annotation.PostConstruct]
last round:false
Note:annotation:PluggableAPT.ToBeTested
Note:--ExecutableElement name is m1
Note:--as=@PluggableAPT.ToBeTested(group="A")
Note:----m1.group=A
Note:--ExecutableElement name is m2
Note:--as=@PluggableAPT.ToBeTested(group="B", owner="QQ")
Note:----m2.group=B
Note:----m2.owner=QQ
Note:--ExecutableElement name is m3
Note:--as=@javax.annotation.PostConstruct
Round2:
input files:{}
annotations:[]
last round:true
input files:{PluggableAPT.Testing}
annotations:[PluggableAPT.ToBeTested, javax.annotation.PostConstruct]
last round:false
Note:annotation:PluggableAPT.ToBeTested
Note:--ExecutableElement name is m1
Note:--as=@PluggableAPT.ToBeTested(group="A")
Note:----m1.group=A
Note:--ExecutableElement name is m2
Note:--as=@PluggableAPT.ToBeTested(group="B", owner="QQ")
Note:----m2.group=B
Note:----m2.owner=QQ
Note:--ExecutableElement name is m3
Note:--as=@javax.annotation.PostConstruct
Round2:
input files:{}
annotations:[]
last round:true
本来想用JDK6.0的Compiler API来执行上面编译命令,可是好像现在Compiler API还不支持-processor参数,运行时总报以下错误
Exception in thread "main" java.lang.IllegalArgumentException: invalid flag: -processor PluggableAPT.MyAnnotationProcessor
调用Compiler API的代码是这样的
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> sourcefiles = fileManager.getJavaFileObjects("Testing.java");
Set<String> options = new HashSet<String>();
options.add("-processor PluggableAPT.MyAnnotationProcessor");
compiler.getTask(null, fileManager, null, options, null, sourcefiles).call();
不知道这是不是Compiler API的一个bug.
(7) JDK6的新特性之七_用Console开发控制台程序
JDK6中提供了java.io.Console类专用来访问基于字符的控制台设备. 你的程序如果要与Windows下的cmd或者Linux下的Terminal交互,就可以用Console类代劳. 但我们不总是能得到可用的Console, 一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用. 如果JVM是在交互式命令行(比如Windows的cmd)中启动的,并且输入输出没有重定向到另外的地方,那么就可以得到一个可用的Console实例. 下面代码演示了Console类的用法:
/**
*/
publicclassConsoleTest {
publicstaticvoidmain(String[] args) {
Console console=System.console();//获得Console实例
if(console!=null){//判断console是否可用
String user=newString(console.readLine("Enter user:"));//读取整行字符
String pwd=newString(console.readPassword("Enter passowrd:"));//读取密码,密码输入时不会显示
console.printf("User is:"+user+"\n");
console.printf("Password is:"+pwd+"\n");
}else{
System.out.println("Console is unavailable");
}
}
}
如果在NetBean5.5里面运行上面程序,会输出*/
publicclassConsoleTest {
publicstaticvoidmain(String[] args) {
Console console=System.console();//获得Console实例
if(console!=null){//判断console是否可用
String user=newString(console.readLine("Enter user:"));//读取整行字符
String pwd=newString(console.readPassword("Enter passowrd:"));//读取密码,密码输入时不会显示
console.printf("User is:"+user+"\n");
console.printf("Password is:"+pwd+"\n");
}else{
System.out.println("Console is unavailable");
}
}
}
Console is unavailable
表示Console不可获得,那是因为JVM不是在命令行中被调用的或者输入输出被重定向了. 但是如果我们在命令行中运行上面程序(java ConsoleTest),程序能够获得Console实例,并执行如下:
Enter user:china
Enter passowrd:
User is:china
Password is:china
在这里可以看到输入密码时,控制台时不显示这些密码字符的,但是程序可以得到输入的密码字符串,这与Linux下面输入密码的情况是一样的
(8) JDK6的新特性之八_嵌入式数据库Derby
Derby并不是一个新的数据库产品,它是由IBM捐献给Apache的DB项目的一个纯Java数据库,JDK6.0里面带的这个Derby的版本是10.2.1.7,支持存储过程和触发器;有两种运行模式,一种是作为嵌入式数据库,另一种是作为网络数据库,前者的数据库服务器和客户端都在同一个JVM里面运行,后者允许数据库服务器端和客户端不在同一个JVM里面,而且允许这两者在不同的物理机器上.值得注意的是JDK6里面的这个Derby支持JDK6的新特性JDBC 4.0规范(JSR 221),现在我们如果要练习JDBC的用法,没有必要单独装一个数据库产品了,直接用Derby就行.安装完JDK6.0后,Derby会被安装到<JDK6_HOME>/db下面,在<JDK6_HOME>/db/demo/programs下面还有一些示例程序,演示了如何启动,连接Derby数据库以及JDBC API的使用.下面分两种情况演示一下如何用代码操作Derby数据库,一种是嵌入式数据库,一种是网络数据库.
一.嵌入式数据库
/**
* @author china
*/
publicclassEmbeddedDerbyTester {
publicstaticvoidmain(String[] args) {
String driver="org.apache.derby.jdbc.EmbeddedDriver";//在derby.jar里面
String dbName="EmbeddedDB";
String dbURL="jdbc:derby:"+dbName+";create=true";//create=true表示当数据库不存在时就创建它
try{
Class.forName(driver);
Connection conn=DriverManager.getConnection(dbURL);//启动嵌入式数据库
Statement st=conn.createStatement();
st.execute("create table foo (FOOID INT NOT NULL,FOONAME VARCHAR(30) NOT NULL)");//创建foo表
st.executeUpdate("insert into foo(FOOID,FOONAME) values (1,'china')");//插入一条数据
ResultSet rs=st.executeQuery("select * from foo");//读取刚插入的数据
while(rs.next()){
intid=rs.getInt(1);
String name=rs.getString(2);
System.out.println("id="+id+";name="+name);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行上面程序后,会在当前目录生成名为EmbeddedDB的文件夹,既是EmbeddedDB数据库的数据文件存放的地方,控制台将输出* @author china
*/
publicclassEmbeddedDerbyTester {
publicstaticvoidmain(String[] args) {
String driver="org.apache.derby.jdbc.EmbeddedDriver";//在derby.jar里面
String dbName="EmbeddedDB";
String dbURL="jdbc:derby:"+dbName+";create=true";//create=true表示当数据库不存在时就创建它
try{
Class.forName(driver);
Connection conn=DriverManager.getConnection(dbURL);//启动嵌入式数据库
Statement st=conn.createStatement();
st.execute("create table foo (FOOID INT NOT NULL,FOONAME VARCHAR(30) NOT NULL)");//创建foo表
st.executeUpdate("insert into foo(FOOID,FOONAME) values (1,'china')");//插入一条数据
ResultSet rs=st.executeQuery("select * from foo");//读取刚插入的数据
while(rs.next()){
intid=rs.getInt(1);
String name=rs.getString(2);
System.out.println("id="+id+";name="+name);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
id=1;name=china
二.网络数据库
/**
* @author china
*/
publicclassNetworkServerDerbyTester {
publicstaticvoidmain(String[] args) {
String driver="org.apache.derby.jdbc.ClientDriver";//在derbyclient.jar里面
String dbName="NetworkDB";
String connectionURL="jdbc:derby://localhost:1527/"+dbName+";create=true";
try{
/*
创建Derby网络服务器,默认端口是1527,也可以通过运行
<Derby_Home>\frameworks\NetworkServer\bin\startNetworkServer.bat
来创建并启动Derby网络服务器,如果是Unix,用startNetworkServer.ksh
*/
NetworkServerControl derbyServer=newNetworkServerControl();//NetworkServerControl类在derbynet.jar里面
PrintWriter pw=newPrintWriter(System.out);//用系统输出作为Derby数据库的输出
derbyServer.start(pw);//启动Derby服务器
Class.forName(driver);
DriverManager.getConnection(connectionURL);
//do something
derbyServer.shutdown();//关闭Derby服务器
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
运行上面程序后,会在当前目录生成名为NetworkDB的文件夹* @author china
*/
publicclassNetworkServerDerbyTester {
publicstaticvoidmain(String[] args) {
String driver="org.apache.derby.jdbc.ClientDriver";//在derbyclient.jar里面
String dbName="NetworkDB";
String connectionURL="jdbc:derby://localhost:1527/"+dbName+";create=true";
try{
/*
创建Derby网络服务器,默认端口是1527,也可以通过运行
<Derby_Home>\frameworks\NetworkServer\bin\startNetworkServer.bat
来创建并启动Derby网络服务器,如果是Unix,用startNetworkServer.ksh
*/
NetworkServerControl derbyServer=newNetworkServerControl();//NetworkServerControl类在derbynet.jar里面
PrintWriter pw=newPrintWriter(System.out);//用系统输出作为Derby数据库的输出
derbyServer.start(pw);//启动Derby服务器
Class.forName(driver);
DriverManager.getConnection(connectionURL);
//do something
derbyServer.shutdown();//关闭Derby服务器
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
关于Derby的详细情况,请参考http://db.apache.org/derby
(9) JDK6的新特性之九_CommonAnnotations
Common annotations原本是Java EE 5.0(JSR 244)规范的一部分,现在SUN把它的一部分放到了Java SE 6.0中.随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,很多Java 技术(比如EJB,Web Services)都会用Annotation部分代替XML文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务), 如果这些技术为通用目的都单独定义了自己的Annotations,显然有点重复建设, 所以,为其他相关的Java技术定义一套公共的Annotation是有价值的,可以避免重复建设的同时,也保证Java SE和Java EE 各种技术的一致性.下面列举出Common Annotations 1.0里面的10个Annotations
Common Annotations
Annotation Retention Target Description
Generated Source ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE 用于标注生成的源代码
Resource Runtime TYPE, METHOD, FIELD 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式
Resources Runtime TYPE 同时标注多个外部依赖,容器会把所有这些外部依赖注入
PostConstruct Runtime METHOD 标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstruct
PreDestroy Runtime METHOD 当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为PreDestroy
RunAs Runtime TYPE 用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container 的Security角色一致的
RolesAllowed Runtime TYPE, METHOD 用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container 的Security角色一致的
PermitAll Runtime TYPE, METHOD 允许所有角色执行被标注的类或方法
DenyAll Runtime TYPE, METHOD 不允许任何角色执行被标注的类或方法,表明该类或方法不能在Java EE容器里面运行
DeclareRoles Runtime TYPE 用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色
Annotation Retention Target Description
Generated Source ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE 用于标注生成的源代码
Resource Runtime TYPE, METHOD, FIELD 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式
Resources Runtime TYPE 同时标注多个外部依赖,容器会把所有这些外部依赖注入
PostConstruct Runtime METHOD 标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为PostConstruct
PreDestroy Runtime METHOD 当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为PreDestroy
RunAs Runtime TYPE 用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container 的Security角色一致的
RolesAllowed Runtime TYPE, METHOD 用于标注允许执行被标注类或方法的安全角色,这个安全角色必须和Container 的Security角色一致的
PermitAll Runtime TYPE, METHOD 允许所有角色执行被标注的类或方法
DenyAll Runtime TYPE, METHOD 不允许任何角色执行被标注的类或方法,表明该类或方法不能在Java EE容器里面运行
DeclareRoles Runtime TYPE 用来定义可以被应用程序检验的安全角色,通常用isUserInRole来检验安全角色
注意:
1.RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上
2.标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的RolesAllowed,PermitAll,DenyAll
3.RunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles还没有加到Java SE 6.0上来
4.处理以上Annotations的工作是由Java EE容器来做, Java SE 6.0只是包含了上面表格的前五种Annotations的定义类,并没有包含处理这些Annotations的引擎,这个工作可以由Pluggable Annotation Processing API(JSR 269)来做
(10) JDK6的新特性之十_Web服务元数据
.Net的Web Services元数据
早在.Net Framework 1.0中,微软就用元数据功能(.net的attribute特性)来标注要暴露成Web Service的方法,下面是用C#演示的利用.net的元数据功能暴露Web Service方法的代码片断.
publicclassTestWS{
[WebMethod]
publicString sayHi(){
return"Hi!";
}
publicintadd(intd1,intd2){
returnd1+d2;
}
}
上面的[WebMethod]是加在方法sayHi上面的元数据,用来告诉Web Services引擎(一般是ASP.NET Runtime), 我这个方法需要暴露为一个Web Service,你需要帮我生成相应的WSDL描述及相关支持文件.而另一个方法add没有加这个元数据,所以Web Services引擎就不会为该方法生成WSDL及相关支持文件[WebMethod]
publicString sayHi(){
return"Hi!";
}
publicintadd(intd1,intd2){
returnd1+d2;
}
}
Java的Web Services元数据
Java 里的Web服务元数据跟微软的方案基本没有语义上的区别,自从JDK5添加了元数据功能(Annotation)之后,SUN几乎重构了整个J2EE体 系, 由于变化很大,干脆将名字也重构为Java EE, Java EE(当前版本为5.0)将元数据纳入很多规范当中,这其中就包括Web Services的相关规范, 加入元数据之后的Web Services服务器端编程模型就跟上面看到的C#片断差不多了, 这显然比以前的JAX-RPC编程模型简单(当然, Axis的编程模型也很简单).这里要谈的Web服务元数据(JSR 181)只是Java Web 服务规范中的一个,它跟Common Annotations, JAXB2, StAX, SAAJ和JAX-WS等共同构成Java EE 5的Web Services技术堆栈.
JSR-181的元数据清单
下面介绍JSR-181里面各个元数据的相关参数及用途
Annotation Retention Target Description
WebService Runtime Type
标注要暴露为Web Services的类或接口
WebParam Runtime Parameter 自定义服务方法参数到WSDL的映射
WebResult Runtime Method 自定义服务方法返回值到WSDL的映射
WebMethod Runtime Method 自定义单个服务方法到WSDL的映射
Oneway Runtime Method 必须与@WebMethod连用,表明被标注方法只有输入没有输出,这就要求被标注方法不能有返回值,也不能声明checked exception
HandlerChain Runtime Type,Method,Field 将Web服务与外部Handler chain关联起来
SOAPBinding Runtime Type,Method 自定义SOAPBinding
WebService Runtime Type
标注要暴露为Web Services的类或接口
WebParam Runtime Parameter 自定义服务方法参数到WSDL的映射
WebResult Runtime Method 自定义服务方法返回值到WSDL的映射
WebMethod Runtime Method 自定义单个服务方法到WSDL的映射
Oneway Runtime Method 必须与@WebMethod连用,表明被标注方法只有输入没有输出,这就要求被标注方法不能有返回值,也不能声明checked exception
HandlerChain Runtime Type,Method,Field 将Web服务与外部Handler chain关联起来
SOAPBinding Runtime Type,Method 自定义SOAPBinding
JSR-181元数据使用示例
packageWebServices;
importjava.io.File;
importjava.io.IOException;
importjavax.jws.Oneway;
importjavax.jws.WebMethod;
importjavax.jws.WebParam;
importjavax.jws.WebResult;
importjavax.jws.WebService;
importjavax.xml.ws.Endpoint;
/**
* @author china
*/
@WebService(targetNamespace="http://blog.csdn.net/china",serviceName="HelloService")
publicclassWSProvider {
@WebResult(name="Greetings")//自定义该方法返回值在WSDL中相关的描述
@WebMethod
publicString sayHi(@WebParam(name="MyName") String name){
return"Hi,"+name;//@WebParam是自定义参数name在WSDL中相关的描述
}
@Oneway//表明该服务方法是单向的,既没有返回值,也不应该声明检查异常
@WebMethod(action="printSystemTime",operationName="printSystemTime")//自定义该方法在WSDL中相关的描述
publicvoidprintTime(){
System.out.println(System.currentTimeMillis());
}
publicstaticvoidmain(String[] args) {
Thread wsPublisher=newThread(newWSPublisher());
wsPublisher.start();
}
privatestaticclassWSPublisherimplementsRunnable{
publicvoidrun() {
//发布WSProvider到http://localhost:8888/china/WSProvider这个地址,之前必须调用wsgen命令
//生成服务类WSProvider的支持类,命令如下:
//wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/china/WSProvider",newWSProvider());
}
}
}
如果想看到Web Services Engine生成的WSDL文件是否遵守上面的元数据, 我们没有必要将上面的WSProvider部署到支持JSR-181的应用服务器或Servlet形式的Web Services Engine,现在JDK6已经提供了一个很简单的机制可以用来测试和发布Web Services,下面讲讲如何在JDK6环境下发布Web
Services和查看生成的WSDLimportjava.io.File;
importjava.io.IOException;
importjavax.jws.Oneway;
importjavax.jws.WebMethod;
importjavax.jws.WebParam;
importjavax.jws.WebResult;
importjavax.jws.WebService;
importjavax.xml.ws.Endpoint;
/**
* @author china
*/
@WebService(targetNamespace="http://blog.csdn.net/china",serviceName="HelloService")
publicclassWSProvider {
@WebResult(name="Greetings")//自定义该方法返回值在WSDL中相关的描述
@WebMethod
publicString sayHi(@WebParam(name="MyName") String name){
return"Hi,"+name;//@WebParam是自定义参数name在WSDL中相关的描述
}
@Oneway//表明该服务方法是单向的,既没有返回值,也不应该声明检查异常
@WebMethod(action="printSystemTime",operationName="printSystemTime")//自定义该方法在WSDL中相关的描述
publicvoidprintTime(){
System.out.println(System.currentTimeMillis());
}
publicstaticvoidmain(String[] args) {
Thread wsPublisher=newThread(newWSPublisher());
wsPublisher.start();
}
privatestaticclassWSPublisherimplementsRunnable{
publicvoidrun() {
//发布WSProvider到http://localhost:8888/china/WSProvider这个地址,之前必须调用wsgen命令
//生成服务类WSProvider的支持类,命令如下:
//wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/china/WSProvider",newWSProvider());
}
}
}
1.将<JDK_HOME>/bin加入path环境变量
2.在命令行下切换当前目录到WSProvider的class文件所在的目录,运行下面命令
wsgen -cp . WebServices.WSProvider
在这个例子中会生成以下3个类的源代码文件及class文件
SayHi
SayHiResponse
PrintTime
3.执行如下代码发布WSProvider到http://localhost:8888/china/WSProvider,在这里可以执行WSProvider类的main方法就可以
Endpoint.publish("http://localhost:8888/china/WSProvider",new WSProvider());
4.在浏览器输入http://localhost:8888/china/WSProvider?wsdl就可以看到生成的WSDL文件,为了节省篇幅,这里就不把生成的WSDL文件贴上了,大家可以自己动手试试.
(11) JDK6的新特性之十一_更简单强大的JAX-WS
AX-WS2.0的来历
--------------------------------------------------------------------------------
JAX-WS(JSR-224) 是Java Architecture for XML Web Services的缩写,简单说就是一种用Java和XML开发Web Services应用程序的框架, 目前版本是2.0, 它是JAX-RPC 1.1的后续版本, J2EE 1.4带的就是JAX-RPC1.1, 而Java EE 5里面包括了JAX-WS 2.0,但为了向后兼容,仍然支持JAX-RPC. 现在,SUN又把JAX-WS直接放到了Java SE 6里面,由于JAX-WS会用到Common Annotation(JSR 250),Java Web Services Metadata(JSR 181), JAXB2(JSR 222), StAX(JSR 173), 所以SUN也必须把后几个原属于Java EE范畴的Components下放到Java SE, 现在我们可以清楚地理解了为什么Sun要把这些看似跟Java SE没有关系的Components放进来,终极目的就是要在Java SE里面支持Web Services.
JAX-WS2.0的架构
--------------------------------------------------------------------------------
JAX-WS不是一个孤立的框架,它依赖于众多其他的规范,本质上它由以下几部分组成
1.用来开发Web Services的Java API
2.用来处理Marshal/Unmarshal的XML Binding机制,JAX-WS2.0用JAXB2来处理Java Object与XML之间的映射,Marshalling就是把Java Object映射到XML,Unmarshalling则是把XML映射到Java Object.之所以要做Java Object与XML的映射,是因为最终作为方法参数和返回值的Java Object要通过网络传输协议(一般是SOAP)传送,这就要求必须对Java Object做类似序列化和反序列化的工作,在SOAP中就是要用XML来表示Java object的内部状态
3.众多元数据(Annotations)会被JAX-WS用来描述Web Services的相关类,包括Common Annotations, Web Services Metadata, JAXB2的元数据和JAX-WS2.0规范自己的元数据.
4.Annotation Processing Tool(APT)是JAX-WS重要的组成部分,由于JAX-WS2.0规范用到很多元数据,所以需要APT来处理众多的Annotations.在<JDK_HOME>/bin下有两个命令wsgen和wsimport,就是用到APT和Compiler API来处理碰到的Annotations,wsgen可以为Web Services Provider产生并编译必要的帮助类和相关支持文件,wsimport以WSDL作为输入为Web Service Consumer产生并编译必要的帮助类和相关支持文件.
5.JAX-WS还包括JAX-WS Runtime与应用服务器和工具之间的契约关系
2.用来处理Marshal/Unmarshal的XML Binding机制,JAX-WS2.0用JAXB2来处理Java Object与XML之间的映射,Marshalling就是把Java Object映射到XML,Unmarshalling则是把XML映射到Java Object.之所以要做Java Object与XML的映射,是因为最终作为方法参数和返回值的Java Object要通过网络传输协议(一般是SOAP)传送,这就要求必须对Java Object做类似序列化和反序列化的工作,在SOAP中就是要用XML来表示Java object的内部状态
3.众多元数据(Annotations)会被JAX-WS用来描述Web Services的相关类,包括Common Annotations, Web Services Metadata, JAXB2的元数据和JAX-WS2.0规范自己的元数据.
4.Annotation Processing Tool(APT)是JAX-WS重要的组成部分,由于JAX-WS2.0规范用到很多元数据,所以需要APT来处理众多的Annotations.在<JDK_HOME>/bin下有两个命令wsgen和wsimport,就是用到APT和Compiler API来处理碰到的Annotations,wsgen可以为Web Services Provider产生并编译必要的帮助类和相关支持文件,wsimport以WSDL作为输入为Web Service Consumer产生并编译必要的帮助类和相关支持文件.
5.JAX-WS还包括JAX-WS Runtime与应用服务器和工具之间的契约关系
JAX-WS2.0的编程模型
--------------------------------------------------------------------------------
现在用JAX-WS2.0来编写Web Services非常简单,不像JAX-RPC,JAX-WS可以把任意POJO暴露为Web Services,服务类不需要实现接口,服务方法也没有必要抛出RMI异常.下面介绍在JDK6环境下用JAX-WS2.0开发和测试Web Services的步骤
1.编写服务类,并用Web Services Metadata(JSR-181)标注这个服务类,我用我的另一篇BlogJDK6的新特性之十:Web服务元数据中的WSProvider类作为服务类的例子,在此我重复贴一下WSProvider类的源代码:
/**
* @author china
*/
@WebService(targetNamespace="http://blog.csdn.net/china",serviceName="HelloService")
publicclassWSProvider {
@WebResult(name="Greetings")//自定义该方法返回值在WSDL中相关的描述
@WebMethod
publicString sayHi(@WebParam(name="MyName") String name){
return"Hi,"+name;//@WebParam是自定义参数name在WSDL中相关的描述
}
@Oneway//表明该服务方法是单向的,既没有返回值,也不应该声明检查异常
@WebMethod(action="printSystemTime",operationName="printSystemTime")//自定义该方法在WSDL中相关的描述
publicvoidprintTime(){
System.out.println(System.currentTimeMillis());
}
publicstaticvoidmain(String[] args) {
Thread wsPublisher=newThread(newWSPublisher());
wsPublisher.start();
}
privatestaticclassWSPublisherimplementsRunnable{
publicvoidrun() {
//发布WSProvider到http://localhost:8888/china/WSProvider这个地址,之前必须调用wsgen命令
//生成服务类WSProvider的支持类,命令如下:
//wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/china/WSProvider",newWSProvider());
}
}
}
2.用wsgen生成上面服务类的必要的帮助类,然后调用用EndPoint类的静态方法publish发布服务类(步骤请参考我的另一篇Blog JDK6的新特性之十:Web服务元数据),我在这里是将服务类发布到http://localhost:8888/china/WSProvider* @author china
*/
@WebService(targetNamespace="http://blog.csdn.net/china",serviceName="HelloService")
publicclassWSProvider {
@WebResult(name="Greetings")//自定义该方法返回值在WSDL中相关的描述
@WebMethod
publicString sayHi(@WebParam(name="MyName") String name){
return"Hi,"+name;//@WebParam是自定义参数name在WSDL中相关的描述
}
@Oneway//表明该服务方法是单向的,既没有返回值,也不应该声明检查异常
@WebMethod(action="printSystemTime",operationName="printSystemTime")//自定义该方法在WSDL中相关的描述
publicvoidprintTime(){
System.out.println(System.currentTimeMillis());
}
publicstaticvoidmain(String[] args) {
Thread wsPublisher=newThread(newWSPublisher());
wsPublisher.start();
}
privatestaticclassWSPublisherimplementsRunnable{
publicvoidrun() {
//发布WSProvider到http://localhost:8888/china/WSProvider这个地址,之前必须调用wsgen命令
//生成服务类WSProvider的支持类,命令如下:
//wsgen -cp . WebServices.WSProvider
Endpoint.publish("http://localhost:8888/china/WSProvider",newWSProvider());
}
}
}
3.用wsimport为服务消费者(也就是服务的客户端)生成必要的帮助类,命令如下:
wsimport http://localhost:8888/china/WSProvider?wsdl
这会在<当前目录>\net\csdn\blog\china下生成客户端的帮助类,在这个例子中会生成7个类
HelloService.class
ObjectFactory.class
package-info.class
PrintSystemTime.class
SayHi.class
SayHiResponse.class
WSProvider.class
4.在客户端用下面代码即可调用步骤1定义的Web ServiceObjectFactory.class
package-info.class
PrintSystemTime.class
SayHi.class
SayHiResponse.class
WSProvider.class
HelloService hs=newHelloService();
WSProvider ws=hs.getWSProviderPort();
System.out.println(ws.sayHi("china"));
ws.printSystemTime();
调用上述代码后客户端控制台输出WSProvider ws=hs.getWSProviderPort();
System.out.println(ws.sayHi("china"));
ws.printSystemTime();
hi,china
服务端控制台输出服务器当前系统时间
(12) JDK6的新特性之十二_脚本语言支持
--------------------------------------------------------------------------------
JDK6增加了对脚本语言的支持(JSR 223),原理上是将脚本语言编译成bytecode,这样脚本语言也能享用Java平台的诸多优势,包括可移植性,安全等,另外,由于现在是编译成bytecode后再执行,所以比原来边解释边执行效率要高很多。加入对脚本语言的支持后,对Java语言也提供了以下好处。
1、许多脚本语言都有动态特性,比如,你不需要用一个变量之前先声明它,你可以用一个变量存放完全不同类型的对象,你不需要做强制类型转换,因为转换都是自动的。现在Java语言也可以通过对脚本语言的支持间接获得这种灵活性。
2、 可以用脚本语言快速开发产品原型,因为现在可以Edit-Run,而无需Edit-Compile-Run,当然,因为Java有非常好的IDE支持,我 们完全可以在IDE里面编辑源文件,然后点击运行(隐含编译),以此达到快速开发原型的目的,所以这点好处基本上可以忽略。
3、通过引入脚本语言可以轻松实现Java应用程序的扩展和自定义,我们可以把原来分布在在Java应用程序中的配置逻辑,数学表达式和业务规则提取出来,转用JavaScript来处理。
Sun的JDK6实现包含了一个基于Mozilla Rhino的 脚本语言引擎,支持JavaScript,这并不是说明JDK6只支持JavaScript,任何第三方都可以自己实现一个JSR-223兼容的脚本引擎 使得JDK6支持别的脚本语言,比如,你想让JDK6支持Ruby,那你可以自己按照JSR
223的规范实现一个Ruby的脚本引擎类,具体一点,你需要实现javax.script.ScriptEngine(简单起见,可以继承javax.script.AbstractScriptEngine)和javax.script.ScriptEngineFactory两个接口。当然,在你实现自己的脚本语言引擎之前,先到scripting.dev.java.net project 这里看看是不是有人已经帮你做了工作,这样你就可以直接拿来用就行。2、 可以用脚本语言快速开发产品原型,因为现在可以Edit-Run,而无需Edit-Compile-Run,当然,因为Java有非常好的IDE支持,我 们完全可以在IDE里面编辑源文件,然后点击运行(隐含编译),以此达到快速开发原型的目的,所以这点好处基本上可以忽略。
3、通过引入脚本语言可以轻松实现Java应用程序的扩展和自定义,我们可以把原来分布在在Java应用程序中的配置逻辑,数学表达式和业务规则提取出来,转用JavaScript来处理。
Scripting API
--------------------------------------------------------------------------------
Scripting API是用于在Java里面编写脚本语言程序的API, 在Javax.script中可以找到Scripting API,我们就是用这个API来编写JavaScript程序,这个包里面有一个ScriptEngineManager类,它是使用Scripting API的入口,ScriptEngineManager可以通过jar服务发现(service discovery)机制寻找合适的脚本引擎类(ScriptEngine),使用Scripting API的最简单方式只需下面三步
1、创建一个ScriptEngineManager对象
2、通过ScriptEngineManager获得ScriptEngine对象
3、用ScriptEngine的eval方法执行脚本
下面是一个Hello World程序
/** * @author china */
publicclassHelloScript {
publicstaticvoidmain(String[] args)throwsException {
ScriptEngineManager factory=newScriptEngineManager();//step 1 ScriptEngine engine = factory.getEngineByName("JavaScript");//Step 2 engine.eval("print('Hello, Scripting')");//Step 3
} }
运行上面程序,控制台会输出Hello, Scripting上面这个简单的Scripting程序演示了如何在Java里面运行脚本语言,除此之外,我们还可以利用Scripting API实现以下功能1、暴露Java对象为脚本语言的全局变量2、在Java中调用脚本语言的方法3、脚本语言可以实现Java的接口4、脚本语言可以像Java一样使用JDK平台下的类下面的类演示了以上4种功能publicclassHelloScript {
publicstaticvoidmain(String[] args)throwsException {
ScriptEngineManager factory=newScriptEngineManager();//step 1 ScriptEngine engine = factory.getEngineByName("JavaScript");//Step 2 engine.eval("print('Hello, Scripting')");//Step 3
} }
packageScripting;
importjava.io.File;
importjavax.script.Invocable;
importjavax.script.ScriptEngine;
importjavax.script.ScriptEngineManager;
importjavax.script.ScriptException;
/** * @author china */
publicclassScriptingAPITester {
publicstaticvoidmain(String[] args)throwsException {
ScriptEngineManager manager=newScriptEngineManager();
ScriptEngine engine=manager.getEngineByName("JavaScript");
testScriptVariables(engine);//演示如何暴露Java对象为脚本语言的全局变量
testInvokeScriptMethod(engine);//演示如何在Java中调用脚本语言的方法
testScriptInterface(engine);//演示脚本语言如何实现Java的接口
testUsingJDKClasses(engine);//演示脚本语言如何使用JDK平台下的类
}
publicstaticvoidtestScriptVariables(ScriptEngine engine)throwsScriptException{
File file=newFile("test.txt");
engine.put("f", file);
engine.eval("println('Total Space:'+f.getTotalSpace())");
}
publicstaticvoidtestInvokeScriptMethod(ScriptEngine engine)throwsException{
String script="function hello(name) { return 'Hello,' + name;}";
engine.eval(script);
Invocable inv=(Invocable) engine;
String res=(String)inv.invokeFunction("hello","Scripting");
System.out.println("res:"+res);
}
publicstaticvoidtestScriptInterface(ScriptEngine engine)throwsScriptException{
String script="var obj = new Object();
obj.run = function() { println('run method called'); }";
engine.eval(script); Object obj=engine.get("obj");
Invocable inv=(Invocable) engine;
Runnable r=inv.getInterface(obj,Runnable.class);
Thread th=newThread(r);
th.start();
}
publicstaticvoidtestUsingJDKClasses(ScriptEngine engine)throwsException{
//Packages是脚本语言里的一个全局变量,专用于访问JDK的package String js = "function doSwing(t){var f=new Packages.javax.swing.JFrame(t);f.setSize(400,300);f.setVisible(true);}";
engine.eval(js);
Invocable inv=(Invocable) engine;
inv.invokeFunction("doSwing","Scripting Swing");
}}
Scripting Tool
importjava.io.File;
importjavax.script.Invocable;
importjavax.script.ScriptEngine;
importjavax.script.ScriptEngineManager;
importjavax.script.ScriptException;
/** * @author china */
publicclassScriptingAPITester {
publicstaticvoidmain(String[] args)throwsException {
ScriptEngineManager manager=newScriptEngineManager();
ScriptEngine engine=manager.getEngineByName("JavaScript");
testScriptVariables(engine);//演示如何暴露Java对象为脚本语言的全局变量
testInvokeScriptMethod(engine);//演示如何在Java中调用脚本语言的方法
testScriptInterface(engine);//演示脚本语言如何实现Java的接口
testUsingJDKClasses(engine);//演示脚本语言如何使用JDK平台下的类
}
publicstaticvoidtestScriptVariables(ScriptEngine engine)throwsScriptException{
File file=newFile("test.txt");
engine.put("f", file);
engine.eval("println('Total Space:'+f.getTotalSpace())");
}
publicstaticvoidtestInvokeScriptMethod(ScriptEngine engine)throwsException{
String script="function hello(name) { return 'Hello,' + name;}";
engine.eval(script);
Invocable inv=(Invocable) engine;
String res=(String)inv.invokeFunction("hello","Scripting");
System.out.println("res:"+res);
}
publicstaticvoidtestScriptInterface(ScriptEngine engine)throwsScriptException{
String script="var obj = new Object();
obj.run = function() { println('run method called'); }";
engine.eval(script); Object obj=engine.get("obj");
Invocable inv=(Invocable) engine;
Runnable r=inv.getInterface(obj,Runnable.class);
Thread th=newThread(r);
th.start();
}
publicstaticvoidtestUsingJDKClasses(ScriptEngine engine)throwsException{
//Packages是脚本语言里的一个全局变量,专用于访问JDK的package String js = "function doSwing(t){var f=new Packages.javax.swing.JFrame(t);f.setSize(400,300);f.setVisible(true);}";
engine.eval(js);
Invocable inv=(Invocable) engine;
inv.invokeFunction("doSwing","Scripting Swing");
}}
Scripting Tool
--------------------------------------------------------------------------------
SUN提供的JDK6中有一个命令行工具??jrunscript,你可以在<JDK6_Home>/bin下面找到这个工具,jrunscript是一个脚本语言的解释程序,它独立于脚本语言,但默认是用JavaScript,我们可以用jrunscript来测试自己写的脚本语言是否正确,下面是一个在命令行运行jrunscript的简单例子
jrunscript
js>println("Hello,JrunScript");
Hello,JrunScript
js>9*8
72.0
js>
js>println("Hello,JrunScript");
Hello,JrunScript
js>9*8
72.0
js>
(13) JDK6的新特性之十三_JTable的排序和过滤
原来的JTable基本上是只能显示数据,在JDK6新增了对JTable的排序和过滤功能,下面代码演示了这两个功能
/**
* @author china
*/
publicclassJTableTester {
staticString data[][]={
{"China","Beijing","Chinese"},
{"America","Washington","English"},
{"Korea","Seoul","Korean"},
{"Japan","Tokyo","Japanese"},
{"France","Paris","French"},
{"England","London","English"},
{"Germany","Berlin","German"},
};
staticString titles[]={"Country","Capital","Language"};
publicstaticvoidmain(String[] args) {
DefaultTableModel m=newDefaultTableModel(data,titles);
JTable t=newJTable(m);
finalTableRowSorter sorter=newTableRowSorter(m);
t.setRowSorter(sorter);//为JTable设置排序器
JScrollPane sPane=newJScrollPane();
sPane.setViewportView(t);
JPanel p=newJPanel();
p.setLayout(newBoxLayout(p,BoxLayout.X_AXIS));
JLabel l=newJLabel("Criteria:");
finalJTextField tf=newJTextField();
JButton b=newJButton("Do Filter");
p.add(l);
p.add(tf);
p.add(b);
b.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
if(tf.getText().length()==0){
sorter.setRowFilter(null);
}else{
sorter.setRowFilter(RowFilter.regexFilter(tf.getText()));//为JTable设置基于正则表达式的过滤条件
}
}
});
JFrame f=newJFrame("JTable Sorting and Filtering");
f.getContentPane().add(sPane,BorderLayout.CENTER);
f.getContentPane().add(p,BorderLayout.SOUTH);
f.setSize(400,300);
f.setVisible(true);
}
}
运行上面程序,单击JTable的某一个title,这个title对应的列就会按照升序/降序重新排列;在下面的Criteria文本框中输入"ese",点击"Do Filter"按钮,JTable将只显示带有"ese"字符串的行,也就是China和Japan两行,如果文本框里面什么都没有,点击"Do
Filter"按钮,这时JTable会显示所有的行。
* @author china
*/
publicclassJTableTester {
staticString data[][]={
{"China","Beijing","Chinese"},
{"America","Washington","English"},
{"Korea","Seoul","Korean"},
{"Japan","Tokyo","Japanese"},
{"France","Paris","French"},
{"England","London","English"},
{"Germany","Berlin","German"},
};
staticString titles[]={"Country","Capital","Language"};
publicstaticvoidmain(String[] args) {
DefaultTableModel m=newDefaultTableModel(data,titles);
JTable t=newJTable(m);
finalTableRowSorter sorter=newTableRowSorter(m);
t.setRowSorter(sorter);//为JTable设置排序器
JScrollPane sPane=newJScrollPane();
sPane.setViewportView(t);
JPanel p=newJPanel();
p.setLayout(newBoxLayout(p,BoxLayout.X_AXIS));
JLabel l=newJLabel("Criteria:");
finalJTextField tf=newJTextField();
JButton b=newJButton("Do Filter");
p.add(l);
p.add(tf);
p.add(b);
b.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
if(tf.getText().length()==0){
sorter.setRowFilter(null);
}else{
sorter.setRowFilter(RowFilter.regexFilter(tf.getText()));//为JTable设置基于正则表达式的过滤条件
}
}
});
JFrame f=newJFrame("JTable Sorting and Filtering");
f.getContentPane().add(sPane,BorderLayout.CENTER);
f.getContentPane().add(p,BorderLayout.SOUTH);
f.setSize(400,300);
f.setVisible(true);
}
}
相关推荐
JDK 12 新特性一览: 189:Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) 230:Microbenchmark Suite 325:Switch Expressions (Preview) 334:JVM Constants API 340:One AArch64 Port, Not ...
8. **日期和时间API**:JDK 8引入了新的`java.time`包,改进了旧有的日期和时间处理。理解和使用LocalDate、LocalTime、ZonedDateTime等类可以提高时间和日期处理的准确性。 9. **泛型**:泛型提高了代码的类型安全...
十、Java 8及以后的新特性 10.1 Lambda表达式:简化匿名内部类,提高代码可读性。 10.2 Stream API:处理集合数据的新方式,提供函数式编程风格。 10.3 Date-Time API:更强大、易用的日期和时间处理库。 以上...
- **系统需求**:MyEclipse 6 要求操作系统为Windows XP SP2或更高版本,Java JDK 1.5或更高版本,至少需要256MB内存,建议512MB或以上。 - **JDK的下载与安装**: - 下载JDK最新版本,通常建议使用JDK 1.5或更高...
- **1.2 JDK的下载,安装和配置(可选):** 提供了JDK 6的下载链接及详细的安装步骤。此外,还介绍了如何配置环境变量以便更好地支持Java开发。 - **1.3 Tomcat服务器的下载,安装和运行(可选):** 指导用户如何...
- JDK6中文文档下载地址 - **Tomcat服务器的下载、安装和运行** - **JBoss服务器的下载、安装和运行** - **MySQL5数据库服务器下载、安装和运行** - **Eclipse3.3的下载、安装和运行** - **MyEclipse6的下载、...
- **JDK6中文文档**:提供中文文档下载地址,方便学习查阅。 - **Tomcat服务器**:介绍如何下载、安装及启动Tomcat服务器,以便进行Web应用测试。 - **JBoss服务器**:类似于Tomcat,但更适用于生产环境的服务器...
这对于定制ROM非常有用,因为它可以在不破坏原有代码结构的情况下增加新特性。 **2. 移植规范** - **2.1 android** Android平台的规范,如API使用规则、编码标准等。 - **2.2 miui** MIUI的特定规范,包括...
文档编写基于Sun JDK 1.5、Eclipse 3.2和MyEclipse 5.0,适用于这些环境下的开发工作。如果遇到理解难题,可以通过用户反馈向MyEclipse文档团队寻求帮助。 2. **准备工作**: - 需要Java 2 SDK 1.4或更高版本。 ...
- Sun JDK 1.5 - Eclipse 3.2 - MyEclipse 5.0 - **适用对象**:主要面向希望通过MyEclipse进行Hibernate开发的学习者或开发者。 #### 2. 准备工作 - **软件要求**: - Java 2 SDK Standard Edition 1.4 或更...
了解机型的硬件特性、驱动支持情况等,有助于更好地进行ROM移植。可以通过访问相关论坛获取更多信息。 ##### 1.2 合适的原厂ROM 寻找官方发布的ROM作为移植的基础非常重要。官方ROM通常具有更好的稳定性和兼容性。...
使用代码插桩技术可以在不改变原始代码结构的情况下,添加新的功能或修改现有功能。 ##### 2. 移植规范 在移植过程中,遵循一定的规范是非常重要的,这样可以确保移植后的ROM具有良好的一致性和扩展性。 ##### ...
它的核心特性在于通过标准化的消息格式、传输协议等,使得服务的使用者能够以独立于服务实现细节的方式调用服务。这意味着Web服务具备松散耦合、面向组件以及跨技术实现的能力。 具体来说,Web服务可以通过以下方式...