001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.imports; 021 022import java.util.ArrayList; 023import java.util.List; 024import java.util.StringTokenizer; 025import java.util.regex.Pattern; 026 027import com.puppycrawl.tools.checkstyle.api.Check; 028import com.puppycrawl.tools.checkstyle.api.DetailAST; 029import com.puppycrawl.tools.checkstyle.api.FullIdent; 030import com.puppycrawl.tools.checkstyle.api.TokenTypes; 031import com.puppycrawl.tools.checkstyle.api.Utils; 032 033/** 034 * <p> 035 * Checks that the groups of import declarations appear in the order specified 036 * by the user. If there is an import but its group is not specified in the 037 * configuration such an import should be placed at the end of the import list. 038 * </p> 039 * The rule consists of: 040 * 041 * <pre> 042 * STATIC group. This group sets the ordering of static imports. 043 * </pre> 044 * 045 * <pre> 046 * SAME_PACKAGE(n) group. This group sets the ordering of the same package imports. 047 * 'n' - a number of the first package domains. For example: 048 * </pre> 049 * 050 * <pre> 051 * <code> 052 * package java.util.concurrent; 053 * 054 * import java.util.regex.Pattern; 055 * import java.util.List; 056 * import java.util.StringTokenizer; 057 * import java.util.regex.Pattern; 058 * import java.util.*; 059 * import java.util.concurrent.AbstractExecutorService; 060 * import java.util.concurrent.*; 061 * 062 * And we have such configuration: SAME_PACKAGE (3). 063 * Same package imports are java.util.*, java.util.concurrent.*, 064 * java.util.concurrent.AbstractExecutorService, 065 * java.util.List and java.util.StringTokenizer 066 * </code> 067 * </pre> 068 * 069 * <pre> 070 * THIRD_PARTY_PACKAGE group. This group sets ordering of third party imports. 071 * Third party imports are all imports except STATIC, 072 * SAME_PACKAGE(n), STANDARD_JAVA_PACKAGE and SPECIAL_IMPORTS. 073 * </pre> 074 * 075 * <pre> 076 * STANDARD_JAVA_PACKAGE group. This group sets ordering of standard java (java|javax) imports. 077 * </pre> 078 * 079 * <pre> 080 * SPECIAL_IMPORTS group. This group may contains some imports 081 * that have particular meaning for the user. 082 * </pre> 083 * 084 * <p> 085 * NOTICE! 086 * </p> 087 * <p> 088 * Use the separator '###' between rules. 089 * </p> 090 * <p> 091 * To set RegExps for THIRD_PARTY_PACKAGE and STANDARD_JAVA_PACKAGE groups use 092 * thirdPartyPackageRegExp and standardPackageRegExp options. 093 * </p> 094 * 095 * <pre> 096 * For example: 097 * </pre> 098 * 099 * <pre> 100 * <code> 101 * <module name="CustomImportOrder"> 102 * <property name="customImportOrderRules" 103 * value="STATIC###SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/> 104 * <property name="thirdPartyPackageRegExp" value="com|org"/> 105 * <property name="standardPackageRegExp" value="java|javax"/> 106 * </module> 107 * </code> 108 * </pre> 109 * <p> 110 * Also, this check can be configured to force empty line separator between 111 * import groups. For example 112 * </p> 113 * 114 * <pre> 115 * <code> 116 * <module name="CustomImportOrder"> 117 * <property name="separateLineBetweenGroups" value="true"/> 118 * </module> 119 * </code> 120 * </pre> 121 * <p> 122 * By the option it is possible to force alphabetically sorting. 123 * </p> 124 * 125 * <pre> 126 * <code> 127 * <module name="CustomImportOrder"> 128 * <property name="sortImportsInGroupAlphabetically" value="true"/> 129 * </module> 130 * </code> 131 * </pre> 132 * 133 * <p> 134 * To force checking imports sequence such as: 135 * </p> 136 * 137 * <pre> 138 * <code> 139 * package com.puppycrawl.tools.checkstyle.imports; 140 * 141 * import com.google.common.annotations.GwtCompatible; 142 * import com.google.common.annotations.Beta; 143 * import com.google.common.annotations.VisibleForTesting; 144 * 145 * import org.abego.treelayout.Configuration; 146 * 147 * import static sun.tools.util.ModifierFilter.ALL_ACCESS; 148 * 149 * import com.google.common.annotations.GwtCompatible; // violation here - should be in the 150 * // THIRD_PARTY_PACKAGE group 151 * import android.*;</code> 152 * </pre> 153 * configure as follows: 154 * <pre> 155 * <code> 156 * <module name="CustomImportOrder"> 157 * <property name="customImportOrderRules" 158 * value="SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STATIC###SPECIAL_IMPORTS"/> 159 * <property name="specialImportsRegExp" value="android.*"/> 160 * </module></code> 161 * </pre> 162 * 163 * @author maxvetrenko 164 * @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a> 165 */ 166public class CustomImportOrderCheck extends Check 167{ 168 169 /** STATIC group name */ 170 private static final String STATIC_RULE_GROUP = "STATIC"; 171 172 /** SAME_PACKAGE group name */ 173 private static final String SAME_PACKAGE_RULE_GROUP = "SAME_PACKAGE"; 174 175 /** THIRD_PARTY_PACKAGE group name */ 176 private static final String THIRD_PARTY_PACKAGE_RULE_GROUP = "THIRD_PARTY_PACKAGE"; 177 178 /** STANDARD_JAVA_PACKAGE group name */ 179 private static final String STANDARD_JAVA_PACKAGE_RULE_GROUP = "STANDARD_JAVA_PACKAGE"; 180 181 /** NON_GROUP group name */ 182 private static final String SPECIAL_IMPORTS_RULE_GROUP = "SPECIAL_IMPORTS"; 183 184 /** NON_GROUP group name */ 185 private static final String NON_GROUP_RULE_GROUP = "NON_GROUP"; 186 187 /** RegExp for SAME_PACKAGE group imports */ 188 private String samePackageDomainsRegExp = ""; 189 190 /** RegExp for STANDARD_JAVA_PACKAGE group imports */ 191 private Pattern standardPackageRegExp = Utils.getPattern("java|javax"); 192 193 /** RegExp for THIRDPARTY_PACKAGE group imports */ 194 private Pattern thirdPartyPackageRegExp = Utils.getPattern(".*"); 195 196 /** RegExp for SPECIAL_IMPORTS group imports */ 197 private Pattern specialImportsRegExp = Utils.getPattern("^$"); 198 199 /** Force empty line separator between import groups */ 200 private boolean separateLineBetweenGroups = true; 201 202 /** Force grouping alphabetically */ 203 private boolean sortImportsInGroupAlphabetically; 204 205 /** List of order declaration customizing by user */ 206 private final List<String> customImportOrderRules = 207 new ArrayList<String>(); 208 209 /** Number of first domains for SAME_PACKAGE group. */ 210 private int samePackageMatchingDepth = 2; 211 212 /** Contains objects with import attributes */ 213 private List<ImportDetails> importToGroupList = 214 new ArrayList<CustomImportOrderCheck.ImportDetails>(); 215 216 /** 217 * Sets standardRegExp specified by user. 218 * @param regexp 219 * user value. 220 */ 221 public final void setStandardPackageRegExp(String regexp) 222 { 223 standardPackageRegExp = Utils.getPattern(regexp); 224 } 225 226 /** 227 * Sets thirdPartyRegExp specified by user. 228 * @param regexp 229 * user value. 230 */ 231 public final void setThirdPartyPackageRegExp(String regexp) 232 { 233 thirdPartyPackageRegExp = Utils.getPattern(regexp); 234 } 235 236 /** 237 * Sets specialImportsRegExp specified by user. 238 * @param regexp 239 * user value. 240 */ 241 public final void setSpecialImportsRegExp(String regexp) 242 { 243 specialImportsRegExp = Utils.getPattern(regexp); 244 } 245 246 /** 247 * Sets separateLineBetweenGroups specified by user. 248 * @param value 249 * user value. 250 */ 251 public final void setSeparateLineBetweenGroups(boolean value) 252 { 253 separateLineBetweenGroups = value; 254 } 255 256 /** 257 * Sets sortImportsInGroupAlphabetically specified by user. 258 * @param value 259 * user value. 260 */ 261 public final void setSortImportsInGroupAlphabetically(boolean value) 262 { 263 sortImportsInGroupAlphabetically = value; 264 } 265 266 /** 267 * Sets a custom import order from the rules in the string format specified 268 * by user. 269 * @param inputCustoimportOrder 270 * user value. 271 */ 272 public final void setCustomImportOrderRules(final String inputCustoimportOrder) 273 { 274 customImportOrderRules.clear(); 275 try { 276 for (String currentState : inputCustoimportOrder 277 .split("\\s*###\\s*")) 278 { 279 addRuleastoList(currentState); 280 } 281 customImportOrderRules.add(NON_GROUP_RULE_GROUP); 282 } 283 catch (StringIndexOutOfBoundsException exp) { 284 //if the structure of the input rule isn't correct 285 throw new RuntimeException("Unable to parse input rule: " + exp); 286 } 287 } 288 289 @Override 290 public int[] getDefaultTokens() 291 { 292 return new int[] { 293 TokenTypes.IMPORT, 294 TokenTypes.STATIC_IMPORT, 295 TokenTypes.PACKAGE_DEF, 296 }; 297 } 298 299 @Override 300 public void beginTree(DetailAST rootAST) 301 { 302 importToGroupList.clear(); 303 } 304 305 @Override 306 public void visitToken(DetailAST ast) 307 { 308 if (ast.getType() == TokenTypes.PACKAGE_DEF) { 309 if (customImportOrderRules.contains(SAME_PACKAGE_RULE_GROUP) 310 && samePackageMatchingDepth != -1) 311 { 312 samePackageDomainsRegExp = createSamePackageRegexp( 313 samePackageMatchingDepth, ast); 314 } 315 } 316 else { 317 final String importFullPath = getFullImportIdent(ast); 318 final int lineNo = ast.getLineNo(); 319 final boolean isStatic = ast.getType() == TokenTypes.STATIC_IMPORT; 320 importToGroupList.add(new ImportDetails(importFullPath, 321 lineNo, getImportGroup(isStatic, importFullPath), 322 isStatic)); 323 } 324 } 325 326 @Override 327 public void finishTree(DetailAST rootAST) 328 { 329 330 if (importToGroupList.isEmpty()) { 331 return; 332 } 333 334 final ImportDetails firstImport = importToGroupList.get(0); 335 String currentGroup = getImportGroup(firstImport.isStatic(), 336 firstImport.getImportFullPath()); 337 int groupNumber = customImportOrderRules.indexOf(currentGroup); 338 String previousImport = null; 339 340 for (ImportDetails importObject : importToGroupList) { 341 final String importGroup = importObject.getImportGroup(); 342 final String fullImportIdent = importObject.importFullPath; 343 344 if (!importGroup.equals(currentGroup)) { 345 if (customImportOrderRules.size() > groupNumber + 1) { 346 final String nextGroup = getNextImportGroup(groupNumber + 1); 347 if (importGroup.equals(nextGroup)) { 348 if (separateLineBetweenGroups && previousImport != null 349 && !hasEmptyLineBefore(importObject.getLineNumber())) 350 { 351 log(importObject.getLineNumber(), "custom.import.order.line.separator", 352 fullImportIdent); 353 } 354 currentGroup = nextGroup; 355 groupNumber = customImportOrderRules.indexOf(nextGroup); 356 } 357 else { 358 logWrongImportGroupOrder(importObject.getLineNumber(), 359 importGroup); 360 } 361 } 362 else { 363 logWrongImportGroupOrder(importObject.getLineNumber(), 364 importGroup); 365 } 366 } 367 else if (sortImportsInGroupAlphabetically 368 && previousImport != null 369 && matchesImportGroup(importObject.isStatic(), 370 fullImportIdent, currentGroup) 371 && !(compareImports(fullImportIdent, previousImport) >= 0)) 372 { 373 log(importObject.getLineNumber(), "custom.import.order.lex", fullImportIdent); 374 } 375 previousImport = fullImportIdent; 376 } 377 } 378 379 /** 380 * Log wrong import group order. 381 * @param currentImportLine 382 * line number of current import current import. 383 * @param importGroup 384 * import group. 385 */ 386 private void logWrongImportGroupOrder(int currentImportLine, String importGroup) 387 { 388 if (NON_GROUP_RULE_GROUP.equals(importGroup)) { 389 log(currentImportLine, "custom.import.order.nongroup.import"); 390 } 391 else { 392 log(currentImportLine, "custom.import.order", importGroup); 393 } 394 } 395 396 /** 397 * Get next import group. 398 * @param currentGroupNumber 399 * current group number. 400 * @return 401 * next import group. 402 */ 403 private String getNextImportGroup(int currentGroupNumber) 404 { 405 int nextGroupNumber = currentGroupNumber; 406 407 while (customImportOrderRules.size() > nextGroupNumber + 1) { 408 if (hasAnyImportInCurrentGroup(customImportOrderRules.get(nextGroupNumber))) 409 { 410 break; 411 } 412 nextGroupNumber++; 413 } 414 return customImportOrderRules.get(nextGroupNumber); 415 } 416 417 /** 418 * Checks if current group contains any import. 419 * @param currentGroup 420 * current group. 421 * @return 422 * true, if current group contains at least one import. 423 */ 424 private boolean hasAnyImportInCurrentGroup(String currentGroup) 425 { 426 for (ImportDetails currentImport : importToGroupList) { 427 if (currentGroup.equals(currentImport.getImportGroup())) { 428 return true; 429 } 430 } 431 return false; 432 } 433 434 /** 435 * Get import valid group. 436 * @param isStatic 437 * is static import. 438 * @param importPath 439 * full import path. 440 * @return import valid group. 441 */ 442 private String getImportGroup(boolean isStatic, String importPath) 443 { 444 for (String group : customImportOrderRules) { 445 if (matchesImportGroup(isStatic, importPath, group)) { 446 return group; 447 } 448 } 449 return NON_GROUP_RULE_GROUP; 450 } 451 452 /** 453 * Checks if the import is placed in the correct group. 454 * @param isStatic 455 * if import is static. 456 * @param importPath 457 * import full path. 458 * @param currentGroup 459 * current group. 460 * @return true, if import placed in the correct group. 461 */ 462 private boolean matchesImportGroup(boolean isStatic, String importPath, String currentGroup) 463 { 464 return matchesStaticImportGroup(isStatic, currentGroup) 465 || matchesSamePackageImportGroup(isStatic, importPath, currentGroup) 466 || matchesSpecialImportsGroup(isStatic, importPath, currentGroup) 467 || matchesStandartImportGroup(isStatic, importPath, currentGroup) 468 || matchesThirdPartyImportGroup(isStatic, importPath, currentGroup); 469 } 470 471 /** 472 * Checks if the import is placed in the STATIC group. 473 * @param isStatic 474 * is static import. 475 * @param currentGroup 476 * current group. 477 * @return true, if the import is placed in the static group. 478 */ 479 private boolean matchesStaticImportGroup(boolean isStatic, String currentGroup) 480 { 481 return isStatic && STATIC_RULE_GROUP.equals(currentGroup); 482 } 483 484 /** 485 * Checks if the import is placed in the correct group. 486 * @param isStatic 487 * if import is static. 488 * @param importFullPath 489 * import full path. 490 * @param currentGroup 491 * current group. 492 * @return true, if the import is placed in the same package group. 493 */ 494 private boolean matchesSamePackageImportGroup(boolean isStatic, 495 String importFullPath, String currentGroup) 496 { 497 final String importPath = importFullPath.substring(0, importFullPath.lastIndexOf(".")); 498 return !isStatic && SAME_PACKAGE_RULE_GROUP.equals(currentGroup) 499 && samePackageDomainsRegExp.contains(importPath); 500 } 501 502 /** 503 * Checks if the import is placed in the correct group. 504 * @param isStatic 505 * if import is static. 506 * @param currentImport 507 * import full path. 508 * @param currentGroup 509 * current group. 510 * @return true, if the import is placed in the standard group. 511 */ 512 private boolean matchesStandartImportGroup(boolean isStatic, 513 String currentImport, String currentGroup) 514 { 515 return !isStatic && STANDARD_JAVA_PACKAGE_RULE_GROUP.equals(currentGroup) 516 && standardPackageRegExp.matcher(currentImport).find(); 517 } 518 519 /** 520 * Checks if the import is placed in the correct group. 521 * @param isStatic 522 * if import is static. 523 * @param currentImport 524 * import full path. 525 * @param currentGroup 526 * current group. 527 * @return true, if the import is placed in the special group. 528 */ 529 private boolean matchesSpecialImportsGroup(boolean isStatic, 530 String currentImport, String currentGroup) 531 { 532 return !isStatic && SPECIAL_IMPORTS_RULE_GROUP.equals(currentGroup) 533 && specialImportsRegExp.matcher(currentImport).find(); 534 } 535 536 /** 537 * Checks if the import is placed in the correct group. 538 * @param isStatic 539 * if import is static. 540 * @param currentImport 541 * import full path. 542 * @param currentGroup 543 * current group. 544 * @return true, if the import is placed in the third party group. 545 */ 546 private boolean matchesThirdPartyImportGroup(boolean isStatic, 547 String currentImport, String currentGroup) 548 { 549 return !isStatic && THIRD_PARTY_PACKAGE_RULE_GROUP.equals(currentGroup) 550 && thirdPartyPackageRegExp.matcher(currentImport).find() 551 && !standardPackageRegExp.matcher(currentImport).find() 552 && !specialImportsRegExp.matcher(currentImport).find(); 553 } 554 555 /** 556 * Checks compare two import paths. 557 * @param import1 558 * current import. 559 * @param import2 560 * previous import. 561 * @return a negative integer, zero, or a positive integer as the 562 * specified String is greater than, equal to, or less 563 * than this String, ignoring case considerations. 564 */ 565 private static int compareImports(String import1, String import2) 566 { 567 int result = 0; 568 final String[] import1Tokens = import1.split("\\."); 569 final String[] import2Tokens = import2.split("\\."); 570 for (int i = 0; i < import1Tokens.length; i++) { 571 if (i == import2Tokens.length) { 572 break; 573 } 574 final String import1Token = import1Tokens[i]; 575 final String import2Token = import2Tokens[i]; 576 result = import1Token.compareToIgnoreCase(import2Token); 577 if (result != 0) { 578 break; 579 } 580 } 581 return result; 582 } 583 584 /** 585 * Return class name from import full path. 586 * @param startFrom number of start. 587 * @param importPath import full path. 588 * @return class name. 589 */ 590 private String getClassName(int startFrom, String importPath) 591 { 592 String className = importPath; 593 className = className.substring(startFrom, className.length()); 594 final StringTokenizer token = new StringTokenizer(className, ".\r"); 595 return token.nextToken(); 596 } 597 598 /** 599 * Checks if a token has a empty line before. 600 * @param lineNo 601 * Line number of current import. 602 * @return true, if token have empty line before. 603 */ 604 private boolean hasEmptyLineBefore(int lineNo) 605 { 606 // [lineNo - 2] is the number of the previous line 607 // because the numbering starts from zero. 608 final String lineBefore = getLine(lineNo - 2); 609 return lineBefore.trim().isEmpty(); 610 } 611 612 /** 613 * Forms import full path. 614 * @param token 615 * current token. 616 * @return full path or null. 617 */ 618 private static String getFullImportIdent(DetailAST token) 619 { 620 return token != null ? FullIdent.createFullIdent(token. 621 findFirstToken(TokenTypes.DOT)).getText() : ""; 622 } 623 624 /** 625 * Parses ordering rule and adds it to the list with rules. 626 * @param ruleStr 627 * String with rule. 628 */ 629 private void addRuleastoList(String ruleStr) 630 { 631 if (STATIC_RULE_GROUP.equals(ruleStr) 632 || THIRD_PARTY_PACKAGE_RULE_GROUP.equals(ruleStr) 633 || STANDARD_JAVA_PACKAGE_RULE_GROUP.equals(ruleStr) 634 || SPECIAL_IMPORTS_RULE_GROUP.equals(ruleStr)) 635 { 636 customImportOrderRules.add(ruleStr); 637 638 } 639 else if (ruleStr.startsWith(SAME_PACKAGE_RULE_GROUP)) { 640 641 final String rule = ruleStr.substring(ruleStr.indexOf("(") + 1, 642 ruleStr.indexOf(")")); 643 try { 644 samePackageMatchingDepth = Integer.parseInt(rule); 645 } 646 catch (Exception e) { 647 samePackageDomainsRegExp = rule; 648 } 649 customImportOrderRules.add(SAME_PACKAGE_RULE_GROUP); 650 651 } 652 else { 653 throw new RuntimeException("Unexpected rule: " + ruleStr); 654 } 655 } 656 657 /** 658 * Creates samePackageDomainsRegExp of the first package domains. 659 * @param firstPackageDomainsCount 660 * number of first package domains. 661 * @param packageNode 662 * package node. 663 * @return same package regexp. 664 */ 665 private static String createSamePackageRegexp(int firstPackageDomainsCount, 666 DetailAST packageNode) 667 { 668 final StringBuilder builder = new StringBuilder(); 669 final String packageFullPath = getFullImportIdent(packageNode); 670 final StringTokenizer tokens = new StringTokenizer(packageFullPath, "."); 671 int count = firstPackageDomainsCount; 672 673 while (tokens.hasMoreTokens() && count > 0) { 674 builder.append(tokens.nextToken()).append("."); 675 count--; 676 } 677 return builder.append("*").toString(); 678 } 679 680 /** 681 * Contains import attributes as line number, import full path, import 682 * group. 683 * @author max 684 */ 685 class ImportDetails 686 { 687 /** Import full path */ 688 private String importFullPath; 689 690 /** Import line number */ 691 private int lineNumber; 692 693 /** Import group */ 694 private String importGroup; 695 696 /** Is static import */ 697 private boolean isStatic; 698 699 /** 700 * @param importFullPath 701 * import full path. 702 * @param lineNumber 703 * import line number. 704 * @param importGroup 705 * import group. 706 * @param isStatic 707 * if import is static. 708 */ 709 public ImportDetails(String importFullPath, 710 int lineNumber, String importGroup, boolean isStatic) 711 { 712 setImportFullPath(importFullPath); 713 setLineNumber(lineNumber); 714 setImportGroup(importGroup); 715 setStatic(isStatic); 716 } 717 718 /** 719 * Get import full path variable. 720 * @return import full path variable. 721 */ 722 public String getImportFullPath() 723 { 724 return importFullPath; 725 } 726 727 /** 728 * Set import full path variable. 729 * @param importFullPath 730 * import full path variable. 731 */ 732 public void setImportFullPath(String importFullPath) 733 { 734 this.importFullPath = importFullPath; 735 } 736 737 /** 738 * Get import line number. 739 * @return import line. 740 */ 741 public int getLineNumber() 742 { 743 return lineNumber; 744 } 745 746 /** 747 * Set import line number. 748 * @param lineNumber 749 * import line number. 750 */ 751 public void setLineNumber(int lineNumber) 752 { 753 this.lineNumber = lineNumber; 754 } 755 756 /** 757 * Get import group. 758 * @return import group. 759 */ 760 public String getImportGroup() 761 { 762 return importGroup; 763 } 764 765 /** 766 * Set import group. 767 * @param importGroup 768 * import group. 769 */ 770 public void setImportGroup(String importGroup) 771 { 772 this.importGroup = importGroup; 773 } 774 775 /** 776 * Checks if import is static. 777 * @return true, if import is static. 778 */ 779 public boolean isStatic() 780 { 781 return isStatic; 782 } 783 784 /** 785 * Set true, if import is static 786 * @param isStatic 787 * if import is static. 788 */ 789 public void setStatic(boolean isStatic) 790 { 791 this.isStatic = isStatic; 792 } 793 } 794}