跳到主要內容

發表文章

目前顯示的是有「SonarLint」標籤的文章

SonarLint | Return of boolean expressions should not be wrapped into an "if-then-else" statement (java:S1126)

Problem private boolean assertFileContainString ( Path filePath, String fileName, String expect ) throws IOException { String content = FileUtil. getContent ( new File ( filePath. resolve ( fileName ) . toString ( ) ) ) ;   if ( content. contains ( expect ) ) // <code smell here!> return true ; return false ; } 這個問題發生在回傳值為boolean,且你寫了不必要的if-then-else。 How to fix? 要解決這問題的方式,就是把不必要的if-then-else直接精簡成一行即可: private boolean assertFileContainString ( Path filePath, String fileName, String expect ) throws IOException { String content = FileUtil. getContent ( new File ( filePath. resolve ( fileName ) . toString ( ) ) ) ; return content. contains ( expect ) ; }

SonarLint | Primitives should not be boxed just for "String" conversion (java:S2131)

Problem 這個問題指的是使用了多此一舉的寫法,先將timeout從primitive type轉為primitive-wrapper type,然後再透過它轉成字串: Integer . valueOf ( timeout ) . toString ( ) ; 這是浪費記憶體與CPU的寫法。 How to fix? 直接透過overloading的toString做轉換即可: Integer . toString ( timeout ) ;

SonarLint | Instance methods should not write to "static" fields (java:S2696)

Problem 這個code smell是再說,使用non-static method去修改static的變數: private static Boolean isDelete = false ;   public String apply ( String content, String url, boolean isDel ) { isDelete = isDel ; // skip } 這意味著可能會因為multi-thread或者是不同instance物件共享到同一個static member,而產生資料錯亂的問題。 How to fix? 這個問題解決方法取決於你的程式邏輯。有幾個可能做法: 將static拿掉。 將修改的method改為有同步保護的static method,例如synchronized static。

SonarLint | A conditionally executed single line should be denoted by indentation (java:S3973)

Problem 這個code smell指的是在if後沒有大括號的情況下,如果下一行沒有縮排,會令維護的人不清楚是要執行或者不執行: public static boolean isValidCodePageOnWindows ( ) {   boolean isCode437 = true ;   if ( PlatformUtil. isLinux ( ) ) return isCode437 ;   // skip } How to fix? 將if的下一行直接縮排即可解決。 public static boolean isValidCodePageOnWindows ( ) {   boolean isCode437 = true ;   if ( PlatformUtil. isLinux ( ) ) return isCode437 ;   // skip }

SonarLint | Switch cases should end with an unconditional "break" statement (java:S128)

Problem 這是個蠻常見的問題,好發於新手或是沒睡飽的人身上。如以下程式碼,如果sensorType是TEMPERATURE,它除了會執行自己區塊的程式碼以外,還會去執行CURRENT部分: switch ( sensorType ) { case TEMPERATURE : // handle1 .. case CURRENT : // handle2 .. break ; default : break ; } How to fix? 修改方法就是記得在個別區塊加上break: switch ( sensorType ) { case TEMPERATURE : // handle1 .. break ; case CURRENT : // handle2 .. break ; default : break ; }

SonarLint | Short-circuit logic should be used in boolean contexts (java:S2178)

Problem 這問題指的是在做邏輯運算時,如果只有使用一個|或一個&,通常都是誤用: if ( test1 ( ) | test2 ( ) ) { // skip } 即使程式碼實際上有照你預期進入block或沒進入block,但當test1()是true時,其實test2()還是會強制被執行的。 How to fix? 只要把一個|改成||即可,這樣如果test1()是true,就會直接執行block中的程式碼: if ( test1 ( ) || test2 ( ) ) { // skip }

SonarLint | Jump statements should not occur in "finally" blocks (java:S1143)

Problem 這問題是發生在finally block中使用return,將會導致拋出的例外遺失,讓client認為這個method正常執行完: } catch ( Exception e ) { throw new JobExecutionException ( e ) ; } finally { if ( isInterrupted ( ) ) { logger. debug ( "[{} job] did not complete." , mJobName ) ; return ; }   pluginState. setEndDate ( ) ; } How to fix? 把return移掉,換個寫法即可。

SonarLint | Printf-style format strings should not lead to unexpected behavior at runtime (java:S2275)

Problem 這個問題是發生在print、formatter、log4j等API,當你該傳入參數是沒傳入時,就可能會被SonarLint找出來。以我的範例來說,是發生在logger.warn的誤用,這會導致輸出的內容將會是{}: } catch ( Exception ex ) { logger. warn ( "get system property error :{}" ,ex ) ; return aDefaultValue ; } How to fix? 假如你只是要印例外的call stack,把{}拿掉即可: logger. warn ( "get system property error" ,ex ) ; 假如你是要印訊息,就直接getMessage: logger. warn ( "get system property error :{}" ,ex. getMessage ( ) ) ;

SonarLint | Resources should be closed (java:S2095)

Problem 以下是一個蠻常見的stream寫法,使用後透過close去關閉: BufferedOutputStream bos = new BufferedOutputStream ( new FileOutputStream ( dirFile ) ) ;   int count ; byte data [ ] = new byte [ BUFFER ] ; while ( ( count = tais. read ( data, 0 , BUFFER ) ) != - 1 ) { bos. write ( data, 0 , count ) ; } bos. close ( ) ;   setPermission ( dirFile, entry. getMode ( ) ) ; 但這個寫法在stream操作過程中,如果發生了例外,將導致steam沒關閉而造成memory leak。 How to fix? 解決方式有兩種,一種是使用try-finally,並將close放在finally block中;另外一種就是直接使用try-with-resources寫法: try ( BufferedOutputStream bos = new BufferedOutputStream ( new FileOutputStream ( dirFile ) ) ; ) { int count ; byte data [ ] = new byte [ BUFFER ] ; while ( ( count = tais. read ( data, 0 , BUFFER ) ) != - 1 ) { bos. write ( data, 0 , count ) ; } } setPermission ( dirFile, entry. getMode ( ) ) ; Notes NIO的Files.walk也是常常被忘記close的stream。

SonarLint | Weak SSL/TLS protocols should not be used (java:S4423)

 Problem 這個問題會發生在使用SSLContext.getInstance傳入一個安全性較弱的protocol種類,以我們的案例來說,我們使用了SSL: final SSLContext sc = SSLContext. getInstance ( "SSL" ) ; sc. init ( null , trustAllCerts, new java. security . SecureRandom ( ) ) ; HttpsURLConnection. setDefaultSSLSocketFactory ( sc. getSocketFactory ( ) ) ; How to fix? 這個問題也屬於find-sec-bug中的SSL_CONTEXT pattern的SSLContext needs to be compatible with TLS 1.2。在SonarLint中,建議將Protocol設定為TLSv1.2,而spotBugs建議為TLS;由於JDK會自己對應TLS的預設值,所以我們選擇設定TLS,在JDK8中預設值為TLSv1.2: final SSLContext sc = SSLContext. getInstance ( "TLS" ) ; sc. init ( null , trustAllCerts, new java. security . SecureRandom ( ) ) ; HttpsURLConnection. setDefaultSSLSocketFactory ( sc. getSocketFactory ( ) ) ;

SonarLint | XML parsers should not be vulnerable to XXE attacks (java:S2755)

Problem 這個問題是由於XML Parser沒有禁止引用外部資源,而讓駭客可以做XXE(XML eXternal Entity Injection)攻擊。這可能會導致伺服器訪問外部網站、造成RCE (Remote Code Execute)、SSRF(Server-Side Request Forgery,讓伺服器訪問外部無法存取的內部網站)、也可以竊取伺服器的敏感資訊。 InputSource src = new InputSource ( new StringReader ( fileContent ) ) ; DocumentBuilderFactory dbFactory = DocumentBuilderFactory. newInstance ( ) ; dbFactory. setNamespaceAware ( true ) ; try { return dbFactory. newDocumentBuilder ( ) . parse ( src ) ; } catch ( SAXException | IOException | ParserConfigurationException e ) { // skip } How to fix? 這段程式碼除了被SonarLint找到問題以外,也被SpotBugs發現一樣問題。在SpotBugs建議的解法是啟用FEATURE_SECURE_PROCESSING,但SonarLint認為這個方法並不完全,而去Disable了外部資源存取: InputSource src = new InputSource ( new StringReader ( fileContent ) ) ; DocumentBuilderFactory dbFactory = DocumentBuilderFactory. newInstance ( ) ; dbFactory. setNamespaceAware ( true ) ; try { dbFactory. setAttribute ( XMLConstants. ACCESS_EXTERNAL_DTD , "" ) ; dbFactory. setAttrib...

SonarLint | How to sort or group issues by severity?

Problem 人的時間有限,在面對海量的issues時,issue severity(嚴重度)是讓你取捨的要素之一。本篇文章分享如何去挑較嚴重的issue出來。 How to? Sort by description 最簡單的第一個方法就是直接點擊description欄位,讓它直接根據嚴重度去排序: Group by severity 第二個方法要在SonarLint On-The-Fly View中使用。假如你這個View沒被打開,可以到Window > Show View中找尋。只有在這個View中,你才能夠使用Group by severty: 這樣你就可以從最嚴重的Blocker開始處理起了。 Note 目前並沒有找到方法可以直接使用Severity去過濾issues,如果之後有會再分享方法。

SonarLint | How to filter issues by description?

Problem 假如你發現有些issue種類特別嚴重,而且你想針對這些特定種類的issue去做處理,你該如何從成千上萬的issues中去找尋呢? How to? 首先可以在SonarLint Report中,點擊View Menu,接著點擊Filter: 在設定畫面中,將你有興趣的issue description如下圖輸入到框起來的text中: 最後在列表中,只會出現你設定的項目: 這樣就可以專注於修復某些特定問題了。

SonarLint | How to filter folder or files in Eclipse?

Problem 剛開始在使用SonarLint掃描專案時,必定會將測試程式碼也一同列出來: 如果不想處理這些東西,或者是想暫時濾掉某些你不想看到的內容;本篇文章將分享給大家,如何在Eclipse上設定,可以讓SonarLint略過某些資料夾與檔案。 How to? Exclude file 第一個方式是直接對你想忽略的檔案按滑鼠右鍵,接著找SonarLint > Exclude即可: 在你設定完成後,進入Project的Properties中,可以在SonarLint > File Exclusions中找到對應設定: 如果反悔要還原直接Remove即可。 Exclude folder 第二個方式適用在於想忽略測試的資料夾。假設我的測試資料夾在src/test,可以在方法一Project的Properties中,使用GLOB type的File Exclusions設定: 這樣設定後,再掃一次專案,就可以發現src/test的內容被濾掉了: Global File Exclusions 假如你的專案很多,不想設定在各別專案上,那可以直接修改全域的設定。打開Window > Preference,在裡面的SonarLint > File Exclusions中,使用如方法二的設定方式即可:

SonarLint(Java)文章列表

Introduction Fix issues before they exist Eclipse HelloWorld Eclipse Filter Configurations How to filter folder or files? How to filter by issue description? How to sort or group issues by severity? Fix code smell Blocker Short-circuit logic should be used in boolean contexts (java:S2178) Switch cases should end with an unconditional "break" statement (java:S128) Critical A conditionally executed single line should be denoted by indentation (java:S3973) Instance methods should not write to "static" fields (java:S2696) Major Primitives should not be boxed just for "String" conversion (java:S2131) Minor Return of boolean expressions should not be wrapped into an "if-then-else" statement (java:S1126) Fix bug Blocker Resources should be closed (java:S2095) Printf-style format strings should not lead to unexpected behavior at runtime (java:S2275) Critical Jump statements should not occur in "finally" blocks (java:S1143) Fix vulnerability Blo...

SonarLint | Eclipse HelloWorld

Introduction 本篇文章分享SonarLint的基本使用方法。 Installation 至Help > Eclipse Marketplace搜尋sonarlint,接著如同其它plugin安裝方式即可完成: Scan Workset/Project/File 你可以選擇Workset、Project或者是File,可以根據你選擇的所有項目或者是有改變的項目去做分析: Check Report 分析完畢後,可以在SonarLint Report的View中確認結果: 它能夠幫你找到Bugs、Code Smells、Security Vulnerability等問題,而icon的含義可以參考下圖(參考於 link ): 嚴重程度Blocker > Critical > Major > Minor > Info。假如看不到SonarLint Report,可以在Window > Show View > Other中,搜尋SonarLint看看。 Fix Issues 在SonarLint Report中點擊issue後,它會連結到對應的source code,有問題的地方會標上藍色底線;將滑鼠移至有問題的地方後,它會提供修正問題的方式或直接取消這條規則: 在你點擊Open description of rule後,它會提供範例與對應的修正方式: Summary 以目前的使用情況來說,被找出來的問題幾乎都是code smell,security與bug的部分較少;有部分的code smell較為嚴格,像是變數修飾字宣告的順序、Lambda寫法需使用method reference、去除不必要的變數assignment等。 如果以建立寫code良好習慣為出發點,可以嘗試安裝這個plugin在你的eclipse上;反正如果你厭煩了某些rule,你是可以deactive那條rule的。 另外這套tool是有支援中央server,讓你制定專案或者是團隊所需要規則;也有支援jenkins plugin,讓你進行持續整合。這些東西如果以後有用到會再分享。 Reference Introduction to SonarQube & SonarLint