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的用法. 

/** 

*/
 
import java.awt.Desktop; 
import java.awt.SystemTray; 
import java.awt.TrayIcon; 
import java.awt.Toolkit; 
import java.awt.Image; 
import java.awt.PopupMenu; 
import java.awt.Menu; 
import java.awt.MenuItem; 
import java.awt.AWTException; 
import java.io.File; 
import java.io.IOException; 
import java.net.URI; 
import java.net.URISyntaxException; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

public class DesktopTray { 
    private static Desktop desktop; 
    private static SystemTray st; 
    private static PopupMenu pm; 
    public static void main(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 = new TrayIcon(image, "Desktop Demo Tray", pm); 
            try { 
                st.add(ti); 
            } catch (AWTException ex) { 
                ex.printStackTrace(); 
            } 
        } 
    } 
    
    public static void sendMail(String mail){ 
        if(desktop!=null && desktop.isSupported(Desktop.Action.MAIL)){ 
            try { 
                desktop.mail(new URI(mail)); 
            } catch (IOException ex) { 
                ex.printStackTrace(); 
            } catch (URISyntaxException ex) { 
                ex.printStackTrace(); 
            } 
        }            
    } 
    
    public static void  openBrowser(String url){ 
        if(desktop!=null && desktop.isSupported(Desktop.Action.BROWSE)){ 
            try { 
                desktop.browse(new URI(url)); 
            } catch (IOException ex) { 
                ex.printStackTrace(); 
            } catch (URISyntaxException ex) { 
                ex.printStackTrace(); 
            } 
        } 
    } 
    
    public static void  edit(){ 
        if(desktop!=null && desktop.isSupported(Desktop.Action.EDIT)){ 
            try { 
                File txtFile = new File("test.txt"); 
                if(!txtFile.exists()){ 
                    txtFile.createNewFile(); 
                } 
                desktop.edit(txtFile); 
            } catch (IOException ex) { 
                ex.printStackTrace(); 
            } 
        } 
    } 
    
    public static void createPopupMenu(){ 
       pm = new PopupMenu(); 
        MenuItem openBrowser = new MenuItem("Open My Blog"); 
        openBrowser.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) { 
                openBrowser("http://blog.csdn.net/china"); 
            } 
        }); 
        
        MenuItem sendMail = new MenuItem("Send Mail to me"); 
        sendMail.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) { 
                sendMail("mailto:[email protected]"); 
            } 
        }); 
        
        MenuItem edit = new MenuItem("Edit Text File"); 
        sendMail.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) { 
                edit(); 
            } 
        }); 
        
        MenuItem exitMenu = new MenuItem("&Exit"); 
        exitMenu.addActionListener(new ActionListener() { 
            public void actionPerformed(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 


(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 

public class JAXB2Tester { 
    public static void main(String[] args) throws JAXBException,IOException { 
        JAXBContext context = JAXBContext.newInstance(Person.class); 
        //下面代碼演示將對象轉變爲xml 
        Marshaller m = context.createMarshaller(); 
        Address address = new Address("China","Beijing","Beijing","ShangDi West","100080"); 
        Person p = new Person(Calendar.getInstance(),"JAXB2",address,Gender.MALE,"SW"); 
        FileWriter fw = new FileWriter("person.xml"); 
        m.marshal(p,fw); 

        //下面代碼演示將上面生成的xml轉換爲對象 
        FileReader fr = new FileReader("person.xml"); 
        Unmarshaller um = context.createUnmarshaller(); 
        Person p2 = (Person)um.unmarshal(fr); 
        System.out.println("Country:"+p2.getAddress().getCountry()); 
    } 


@XmlRootElement//表示person是一個根元素 
class Person {    
    @XmlElement 
    Calendar birthDay; //birthday將作爲person的子元素 

    @XmlAttribute 
    String name; //name將作爲person的的一個屬性 

    public Address getAddress() { 
        return address; 
    } 

    @XmlElement 
    Address address; //address將作爲person的子元素 

    @XmlElement 
    Gender gender; //gender將作爲person的子元素 

    @XmlElement 
    String job; //job將作爲person的子元素 

    public Person(){ 
    } 
    
    public Person(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); 
    private boolean value; 
    Gender(boolean _value){ 
        value = _value; 
    } 


class Address { 
    @XmlAttribute 
    String country; 
    @XmlElement 
    String state; 
    @XmlElement 
    String city; 
    @XmlElement 
    String street; 
    String zipcode; //由於沒有添加@XmlElement,所以該元素不會出現在輸出的xml中 

    public Address() { 
    } 

    public Address(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; 
    } 


    public String getCountry() { 
        return country; 
    } 

運行該程序,我們會得到一個person.xml的文件,如下: 

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 

<person name="JAXB2"
      <birthDay>2006-12-28T08:49:27.203+00:00</birthDay> 
       <address country="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文檔 

public class StaxTester { 
    public static void main(String[] args) throws XMLStreamException, FileNotFoundException { 
        readXMLByStAX();//用XMLEventReader解析xml文檔 
        writeXMLByStAX();//用XMLStreamWriter寫xml文檔 
    } 

    private static void readXMLByStAX() throws XMLStreamException, FileNotFoundException { 
        XMLInputFactory xmlif = XMLInputFactory.newInstance(); 
        XMLEventReader xmler = xmlif.createXMLEventReader(StaxTester.class.getResourceAsStream("test.xml")); 
        XMLEvent event; 
        StringBuffer parsingResult = new StringBuffer(); 
        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(new QName("id")).getValue()); 
                    parsingResult.append("\""); 
                } 
                parsingResult.append(">"); 
            } else if (event.isCharacters()) { //如果解析的是文本內容 
                parsingResult.append(event.asCharacters().getData()); 
            } else if(event.isEndElement()){ //如果解析的是結束標記 
                parsingResult.append("</"); 
                parsingResult.append(event.asEndElement().getName()); 
                parsingResult.append(">"); 
            } 
        } 
        System.out.println(parsingResult); 
    } 

    private static void writeXMLByStAX() throws XMLStreamException, FileNotFoundException { 
        XMLOutputFactory xmlof = XMLOutputFactory.newInstance(); 
        XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream("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文件內容如下: 

<?xml version="1.0" encoding="UTF-8"?> 
<catalogs> 
    <catalog id="001">Book</catalog> 
    <catalog id="002">Video</catalog> 
</catalogs> 

運行上面程序後,控制檯輸出如下: 

<catalogs> 
    <catalog id="001">Book</catalog> 
    <catalog id="002">Video</catalog> 
</catalogs> 

運行上面程序後,產生的output.xml文件如下: 

<?xml version="1.0" ?> 
<!-- testing comment--> 
<catalogs xmlns:myNS="http://blog.csdn.net/China" owner="China"
    <myNS:catalog id="007">Apparel</myNS:catalog> 
</catalogs> 
(4) JDK6的新特性之四_使用Compiler API 

現在我們可以用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的使用 

public class CompilerAPITester { 
    private static String JAVA_SOURCE_FILE = "DynamicObject.java"
    private static String JAVA_CLASS_FILE = "DynamicObject.class"
    private static String JAVA_CLASS_NAME = "DynamicObject"
    public static void main(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<? extends JavaFileObject> 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(); 
        } 
    } 

    public static void generateJavaClass(){ 
        try { 
            FileWriter fw = new FileWriter(JAVA_SOURCE_FILE); 
            BufferedWriter bw = new BufferedWriter(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 
*/
 
public class HTTPServerAPITester { 
    public static void main(String[] args) { 
        try { 
            HttpServer hs = HttpServer.create(new InetSocketAddress(8888),0);//設置HttpServer的端口爲8888 
            hs.createContext("/china"new MyHandler());//用MyHandler類內處理到/china的請求 
            hs.setExecutor(null); // creates a default executor 
            hs.start(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 


class MyHandler implements HttpHandler { 
   public void handle(HttpExchange t) throws IOException { 
       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 
public void testCheckName(){ 
       //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) 
public class MyAnnotationProcessor extends AbstractProcessor { 
    private void note(String msg) { 
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg); 
    } 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
        //annotations的值是通過@SupportedAnnotationTypes聲明的且目標源代碼擁有的所有Annotations 
        for(TypeElement te:annotations){ 
            note("annotation:"+te.toString()); 
        } 
        Set<? extends Element> elements = roundEnv.getRootElements();//獲取源代碼的映射對象 
        for(Element e:elements){ 
            //獲取源代碼對象的成員 
            List<? extends Element> enclosedElems = e.getEnclosedElements(); 
            //留下方法成員,過濾掉其他成員 
            List<? extends ExecutableElement> ees = ElementFilter.methodsIn(enclosedElems); 
            for(ExecutableElement ee:ees){ 
                note("--ExecutableElement name is "+ee.getSimpleName()); 
                List<? extends AnnotationMirror> as = ee.getAnnotationMirrors();//獲取方法的Annotations 
                note("--as="+as); 
                for(AnnotationMirror am:as){ 
                    //獲取Annotation的值 
                    Map<? extends ExecutableElement, ? extends AnnotationValue> map= am.getElementValues(); 
                    Set<? extends ExecutableElement> ks = map.keySet(); 
                    for(ExecutableElement k:ks){//打印Annotation的每個值 
                        AnnotationValue av = map.get(k); 
                        note("----"+ee.getSimpleName()+"."+k.getSimpleName()+"="+av.getValue()); 
                    } 
                } 
            } 
        } 
        return false; 
    } 


@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
@interface ToBeTested{ 
    String owner() default "China"
    String group(); 

編譯以上代碼,然後再創建下面的Testing對象,不要編譯Testing對象,我在後面會編譯它 

public class Testing{    
    @ToBeTested(group="A"
    public void m1(){ 
    } 
    @ToBeTested(group="B",owner="QQ"
    public void m2(){ 
    }    
    @PostConstruct//Common Annotation裏面的一個Annotation 
    public void m3(){ 
    }    

下面我用以下命令編譯Testing對象 

javac -XprintRounds -processor PluggableAPT.MyAnnotationProcessor Testing.java 
-XprintRounds表示打印round的次數,運行上面命令後在控制檯會看到如下輸出: 

Round 1: 
        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=
Note: --ExecutableElement name is m2 
Note: --as=@PluggableAPT.ToBeTested(group="B", owner="QQ"
Note: ----m2.group=
Note: ----m2.owner=QQ 
Note: --ExecutableElement name is m3 
Note: --as=@javax.annotation.PostConstruct 
Round 2: 
        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類的用法: 

/** 
*/
 
public class ConsoleTest { 
    
    public static void main(String[] args) { 
        Console console = System.console();//獲得Console實例 
        if(console!=null){//判斷console是否可用 
            String user = new String(console.readLine("Enter user:")); //讀取整行字符 
            String pwd = new String(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裏面運行上面程序,會輸出 

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 
*/
 
public class EmbeddedDerbyTester { 
    public static void main(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()){ 
                int id = rs.getInt(1); 
                String name = rs.getString(2); 
                System.out.println("id="+id+";name="+name); 
            } 
        } catch(Exception e){ 
            e.printStackTrace(); 
        } 
    } 

運行上面程序後,會在當前目錄生成名爲EmbeddedDB的文件夾,既是EmbeddedDB數據庫的數據文件存放的地方,控制檯將輸出 

id=1;name=china 

二.網絡數據庫 

/** 
* @author china 
*/
 
public class NetworkServerDerbyTester { 
    public static void main(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 = new NetworkServerControl();//NetworkServerControl類在derbynet.jar裏面 
            PrintWriter pw = new PrintWriter(System.out);//用系統輸出作爲Derby數據庫的輸出 
            derbyServer.start(pw);//啓動Derby服務器 
            Class.forName(driver); 
            DriverManager.getConnection(connectionURL); 
            //do something 
            derbyServer.shutdown();//關閉Derby服務器 
        } catch (Exception ex) { 
            ex.printStackTrace(); 
        } 
    } 

運行上面程序後,會在當前目錄生成名爲NetworkDB的文件夾 

關於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來檢驗安全角色 


注意: 

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方法的代碼片斷. 
public class TestWS{ 
    [WebMethod] 
    public String sayHi(){ 
          return "Hi!"
    }    
    public int add(int d1,int d2){ 
          return d1+d2; 
    } 
上面的[WebMethod]是加在方法sayHi上面的元數據,用來告訴Web Services引擎(一般是ASP.NET Runtime), 我這個方法需要暴露爲一個Web Service,你需要幫我生成相應的WSDL描述及相關支持文件.而另一個方法add沒有加這個元數據,所以Web Services引擎就不會爲該方法生成WSDL及相關支持文件 

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 

JSR-181元數據使用示例 

package WebServices; 

import java.io.File; 
import java.io.IOException; 
import javax.jws.Oneway; 
import javax.jws.WebMethod; 
import javax.jws.WebParam; 
import javax.jws.WebResult; 
import javax.jws.WebService; 
import javax.xml.ws.Endpoint; 

/** 
* @author china 
*/
 
@WebService(targetNamespace="http://blog.csdn.net/china",serviceName="HelloService"
public class WSProvider { 
    @WebResult(name="Greetings")//自定義該方法返回值在WSDL中相關的描述    
    @WebMethod 
    public String sayHi(@WebParam(name="MyName") String name){ 
        return "Hi,"+name; //@WebParam是自定義參數name在WSDL中相關的描述 
    }    
    @Oneway //表明該服務方法是單向的,既沒有返回值,也不應該聲明檢查異常 
    @WebMethod(action="printSystemTime",operationName="printSystemTime")//自定義該方法在WSDL中相關的描述 
    public void printTime(){ 
        System.out.println(System.currentTimeMillis()); 
    } 
    public static void main(String[] args) { 
        Thread wsPublisher = new Thread(new WSPublisher()); 
        wsPublisher.start(); 
    }    
    private static class WSPublisher implements Runnable{ 
        public void run() { 
            //發佈WSProvider到http://localhost:8888/china/WSProvider這個地址,之前必須調用wsgen命令 
            //生成服務類WSProvider的支持類,命令如下: 
            //wsgen -cp . WebServices.WSProvider 
            Endpoint.publish("http://localhost:8888/china/WSProvider",new WSProvider()); 
        }        
    } 

如果想看到Web Services Engine生成的WSDL文件是否遵守上面的元數據, 我們沒有必要將上面的WSProvider部署到支持JSR-181的應用服務器或Servlet形式的Web Services Engine,現在JDK6已經提供了一個很簡單的機制可以用來測試和發佈Web Services,下面講講如何在JDK6環境下發布Web Services和查看生成的WSDL 
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與應用服務器和工具之間的契約關係 

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"
public class WSProvider { 
    @WebResult(name="Greetings")//自定義該方法返回值在WSDL中相關的描述    
    @WebMethod 
    public String sayHi(@WebParam(name="MyName") String name){ 
        return "Hi,"+name; //@WebParam是自定義參數name在WSDL中相關的描述 
    }    
    @Oneway //表明該服務方法是單向的,既沒有返回值,也不應該聲明檢查異常 
    @WebMethod(action="printSystemTime",operationName="printSystemTime")//自定義該方法在WSDL中相關的描述 
    public void printTime(){ 
        System.out.println(System.currentTimeMillis()); 
    } 
    public static void main(String[] args) { 
        Thread wsPublisher = new Thread(new WSPublisher()); 
        wsPublisher.start(); 
    }    
    private static class WSPublisher implements Runnable{ 
        public void run() { 
            //發佈WSProvider到http://localhost:8888/china/WSProvider這個地址,之前必須調用wsgen命令 
            //生成服務類WSProvider的支持類,命令如下: 
            //wsgen -cp . WebServices.WSProvider 
            Endpoint.publish("http://localhost:8888/china/WSProvider",new WSProvider()); 
        }        
    } 
2.用wsgen生成上面服務類的必要的幫助類,然後調用用EndPoint類的靜態方法publish發佈服務類(步驟請參考我的另一篇Blog JDK6的新特性之十:Web服務元數據),我在這裏是將服務類發佈到http://localhost:8888/china/WSProvider 
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 Service 
HelloService hs = new HelloService(); 
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 這裏看看是不是有人已經幫你做了工作,這樣你就可以直接拿來用就行。 

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 */ 
public class HelloScript { 
public static void main(String[] args) throws Exception { 
ScriptEngineManager factory = new ScriptEngineManager();//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種功能 
package Scripting; 
import java.io.File; 
import javax.script.Invocable; 
import javax.script.ScriptEngine; 
import javax.script.ScriptEngineManager; 
import javax.script.ScriptException; 
/** * @author china */ 
public class ScriptingAPITester { 
public static void main(String[] args) throws Exception { 
        ScriptEngineManager manager = new ScriptEngineManager(); 
        ScriptEngine engine = manager.getEngineByName("JavaScript"); 
        testScriptVariables(engine);//演示如何暴露Java對象爲腳本語言的全局變量 
        testInvokeScriptMethod(engine);//演示如何在Java中調用腳本語言的方法 
        testScriptInterface(engine);//演示腳本語言如何實現Java的接口 
         testUsingJDKClasses(engine);//演示腳本語言如何使用JDK平臺下的類 
    } 
        public static void testScriptVariables(ScriptEngine engine) throws ScriptException{ 
        File file = new File("test.txt"); 
        engine.put("f", file); 
        engine.eval("println('Total Space:'+f.getTotalSpace())"); 
            } 
        public static void testInvokeScriptMethod(ScriptEngine engine) throws Exception{ 
        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); 
    } 

        public static void testScriptInterface(ScriptEngine engine) throws ScriptException{ 
        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 = new Thread(r); 
        th.start(); 
    } 
        public static void testUsingJDKClasses(ScriptEngine engine) throws Exception{ 
        //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> 

(13) JDK6的新特性之十三_JTable的排序和過濾 

原來的JTable基本上是隻能顯示數據,在JDK6新增了對JTable的排序和過濾功能,下面代碼演示了這兩個功能 

/** 
* @author china 
*/
 
public class JTableTester { 
    static String data[][] = { 
        {"China","Beijing","Chinese"}, 
        {"America","Washington","English"}, 
        {"Korea","Seoul","Korean"}, 
        {"Japan","Tokyo","Japanese"}, 
        {"France","Paris","French"}, 
        {"England","London","English"}, 
        {"Germany","Berlin","German"}, 
    }; 
    static String titles[] = {"Country","Capital","Language"}; 
    public static void main(String[] args) {        
        DefaultTableModel m = new DefaultTableModel(data,titles); 
        JTable t = new JTable(m); 
        final TableRowSorter sorter = new TableRowSorter(m); 
        t.setRowSorter(sorter); //爲JTable設置排序器 
        
        JScrollPane sPane = new JScrollPane(); 
        sPane.setViewportView(t); 
        
        JPanel p = new JPanel(); 
        p.setLayout(new BoxLayout(p,BoxLayout.X_AXIS)); 
        JLabel l = new JLabel("Criteria:"); 
        final JTextField tf = new JTextField(); 
        JButton b = new JButton("Do Filter"); 
        p.add(l); 
        p.add(tf); 
        p.add(b); 
        b.addActionListener(new ActionListener() { 
            public void actionPerformed(ActionEvent e) { 
                if(tf.getText().length()==0){ 
                    sorter.setRowFilter(null); 
                }else
                    sorter.setRowFilter(RowFilter.regexFilter(tf.getText()));//爲JTable設置基於正則表達式的過濾條件 
                } 
            } 
        }); 
        
        JFrame f = new JFrame("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會顯示所有的行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章