001 /** 002 * Copyright (c) 2000-present Liferay, Inc. All rights reserved. 003 * 004 * This library is free software; you can redistribute it and/or modify it under 005 * the terms of the GNU Lesser General Public License as published by the Free 006 * Software Foundation; either version 2.1 of the License, or (at your option) 007 * any later version. 008 * 009 * This library is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 011 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 012 * details. 013 */ 014 015 package com.liferay.portal.tools.sourceformatter; 016 017 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader; 018 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader; 019 import com.liferay.portal.kernel.util.ArrayUtil; 020 import com.liferay.portal.kernel.util.CharPool; 021 import com.liferay.portal.kernel.util.ListUtil; 022 import com.liferay.portal.kernel.util.StringBundler; 023 import com.liferay.portal.kernel.util.StringPool; 024 import com.liferay.portal.kernel.util.StringUtil; 025 import com.liferay.portal.kernel.util.Tuple; 026 import com.liferay.portal.kernel.util.Validator; 027 028 import com.thoughtworks.qdox.JavaDocBuilder; 029 import com.thoughtworks.qdox.model.JavaMethod; 030 031 import java.io.File; 032 033 import java.util.ArrayList; 034 import java.util.Iterator; 035 import java.util.List; 036 import java.util.Set; 037 import java.util.TreeSet; 038 import java.util.regex.Matcher; 039 import java.util.regex.Pattern; 040 041 /** 042 * @author Hugo Huijser 043 */ 044 public class JavaClass { 045 046 public JavaClass( 047 String name, String packagePath, File file, String fileName, 048 String absolutePath, String content, int lineCount, String indent, 049 JavaClass outerClass, 050 List<String> javaTermAccessLevelModifierExclusions) 051 throws Exception { 052 053 _name = name; 054 _packagePath = packagePath; 055 _file = file; 056 _fileName = fileName; 057 _absolutePath = absolutePath; 058 _content = content; 059 _lineCount = lineCount; 060 _indent = indent; 061 _outerClass = outerClass; 062 _javaTermAccessLevelModifierExclusions = 063 javaTermAccessLevelModifierExclusions; 064 065 _javaTerms = getJavaTerms(); 066 } 067 068 public String formatJavaTerms( 069 Set<String> annotationsExclusions, Set<String> immutableFieldTypes, 070 List<String> checkJavaFieldTypesExclusions, 071 List<String> javaTermSortExclusions, 072 List<String> testAnnotationsExclusions) 073 throws Exception { 074 075 if ((_javaTerms == null) || _javaTerms.isEmpty()) { 076 return _content; 077 } 078 079 String originalContent = _content; 080 081 JavaTerm previousJavaTerm = null; 082 083 Iterator<JavaTerm> itr = _javaTerms.iterator(); 084 085 while (itr.hasNext()) { 086 JavaTerm javaTerm = itr.next(); 087 088 if (javaTerm.isConstructor()) { 089 checkConstructor(javaTerm); 090 } 091 092 checkUnusedParameters(javaTerm); 093 094 if (!BaseSourceProcessor.isExcluded( 095 checkJavaFieldTypesExclusions, _absolutePath)) { 096 097 checkJavaFieldType( 098 javaTerm, annotationsExclusions, immutableFieldTypes); 099 } 100 101 if (!originalContent.equals(_content)) { 102 return _content; 103 } 104 105 sortJavaTerms(previousJavaTerm, javaTerm, javaTermSortExclusions); 106 fixTabsAndIncorrectEmptyLines(javaTerm); 107 formatAnnotations(javaTerm, testAnnotationsExclusions); 108 109 if (!originalContent.equals(_content)) { 110 return _content; 111 } 112 113 previousJavaTerm = javaTerm; 114 } 115 116 for (JavaClass innerClass : _innerClasses) { 117 String innerClassContent = innerClass.getContent(); 118 119 String newInnerClassContent = innerClass.formatJavaTerms( 120 annotationsExclusions, immutableFieldTypes, 121 checkJavaFieldTypesExclusions, javaTermSortExclusions, 122 testAnnotationsExclusions); 123 124 if (!innerClassContent.equals(newInnerClassContent)) { 125 _content = StringUtil.replace( 126 _content, innerClassContent, newInnerClassContent); 127 128 return _content; 129 } 130 } 131 132 fixJavaTermsDividers(_javaTerms, javaTermSortExclusions); 133 134 return _content; 135 } 136 137 public String getContent() { 138 return _content; 139 } 140 141 protected Set<JavaTerm> addStaticBlocks( 142 Set<JavaTerm> javaTerms, List<JavaTerm> staticBlocks) { 143 144 Set<JavaTerm> newJavaTerms = new TreeSet<JavaTerm>( 145 new JavaTermComparator()); 146 147 Iterator<JavaTerm> javaTermsIterator = javaTerms.iterator(); 148 149 while (javaTermsIterator.hasNext()) { 150 JavaTerm javaTerm = javaTermsIterator.next(); 151 152 if (!javaTerm.isStatic() || !javaTerm.isVariable()) { 153 newJavaTerms.add(javaTerm); 154 155 continue; 156 } 157 158 Iterator<JavaTerm> staticBlocksIterator = staticBlocks.iterator(); 159 160 while (staticBlocksIterator.hasNext()) { 161 JavaTerm staticBlock = staticBlocksIterator.next(); 162 163 String staticBlockContent = staticBlock.getContent(); 164 165 if (staticBlockContent.contains(javaTerm.getName())) { 166 staticBlock.setType(javaTerm.getType() + 1); 167 168 newJavaTerms.add(staticBlock); 169 170 staticBlocksIterator.remove(); 171 } 172 } 173 174 newJavaTerms.add(javaTerm); 175 } 176 177 if (!staticBlocks.isEmpty()) { 178 newJavaTerms.addAll(staticBlocks); 179 } 180 181 return newJavaTerms; 182 } 183 184 protected void checkAnnotationForMethod( 185 JavaTerm javaTerm, String annotation, String requiredMethodNameRegex, 186 int requiredMethodType, String fileName) { 187 188 String methodContent = javaTerm.getContent(); 189 String methodName = javaTerm.getName(); 190 191 Pattern pattern = Pattern.compile(requiredMethodNameRegex); 192 193 Matcher matcher = pattern.matcher(methodName); 194 195 if (methodContent.contains( 196 _indent + StringPool.AT + annotation + "\n") || 197 methodContent.contains( 198 _indent + StringPool.AT + annotation + 199 StringPool.OPEN_PARENTHESIS)) { 200 201 if (!matcher.find()) { 202 BaseSourceProcessor.processErrorMessage( 203 fileName, 204 "LPS-36303: Incorrect method name: " + methodName + " " + 205 fileName); 206 } 207 else if (javaTerm.getType() != requiredMethodType) { 208 BaseSourceProcessor.processErrorMessage( 209 fileName, 210 "LPS-36303: Incorrect method type for " + methodName + " " + 211 fileName); 212 } 213 } 214 else if (matcher.find() && 215 !methodContent.contains(_indent + "@Override")) { 216 217 BaseSourceProcessor.processErrorMessage( 218 fileName, 219 "Annotation @" + annotation + " required for " + methodName + 220 " " + fileName); 221 } 222 } 223 224 protected void checkConstructor(JavaTerm javaTerm) throws Exception { 225 String javaTermContent = javaTerm.getContent(); 226 227 if (javaTermContent.contains(StringPool.TAB + "super();")) { 228 String newJavaTermContent = StringUtil.replace( 229 javaTermContent, StringPool.TAB + "super();", StringPool.BLANK); 230 231 _content = StringUtil.replace( 232 _content, javaTermContent, newJavaTermContent); 233 234 return; 235 } 236 237 if (!ListUtil.isEmpty(javaTerm.getParameterTypes())) { 238 checkConstructorParameterOrder(javaTerm); 239 240 return; 241 } 242 243 if ((_packagePath == null) || (_constructorCount > 1) || 244 !javaTermContent.contains("{\n" + _indent + "}\n")) { 245 246 return; 247 } 248 249 String accessModifier = getAccessModifier(); 250 251 if ((javaTerm.isPrivate() && 252 !accessModifier.equals(_ACCESS_MODIFIER_PRIVATE)) || 253 (javaTerm.isProtected() && 254 !accessModifier.equals(_ACCESS_MODIFIER_PRIVATE) && 255 !accessModifier.equals(_ACCESS_MODIFIER_PROTECTED))) { 256 257 return; 258 } 259 260 Pattern pattern = Pattern.compile("class " + _name + "[ \t\n]+extends"); 261 262 Matcher matcher = pattern.matcher(_content); 263 264 if (!matcher.find()) { 265 return; 266 } 267 268 JavaDocBuilder javaDocBuilder = new JavaDocBuilder(); 269 270 javaDocBuilder.addSource(_file); 271 272 com.thoughtworks.qdox.model.JavaClass javaClass = 273 javaDocBuilder.getClassByName( 274 _packagePath + StringPool.PERIOD + _name); 275 276 com.thoughtworks.qdox.model.JavaClass superJavaClass = 277 javaClass.getSuperJavaClass(); 278 279 JavaMethod superJavaClassConstructor = 280 superJavaClass.getMethodBySignature(superJavaClass.getName(), null); 281 282 if ((superJavaClassConstructor != null) && 283 ArrayUtil.isEmpty(superJavaClassConstructor.getExceptions())) { 284 285 _content = StringUtil.replace( 286 _content, javaTermContent, StringPool.BLANK); 287 } 288 } 289 290 protected void checkConstructorParameterOrder(JavaTerm javaTerm) { 291 int previousPos = -1; 292 293 for (String parameterName : javaTerm.getParameterNames()) { 294 Pattern pattern = Pattern.compile( 295 "\\{\n([\\s\\S]*?)(_" + parameterName + " =[ \t\n]+" + 296 parameterName + ";)"); 297 298 Matcher matcher = pattern.matcher(javaTerm.getContent()); 299 300 if (!matcher.find()) { 301 continue; 302 } 303 304 String beforeParameter = matcher.group(1); 305 306 if (beforeParameter.contains(parameterName + " =")) { 307 continue; 308 } 309 310 int pos = matcher.start(2); 311 312 if (previousPos > pos) { 313 BaseSourceProcessor.processErrorMessage( 314 _fileName, 315 "Constructor parameter order " + parameterName + ": " + 316 _fileName); 317 318 return; 319 } 320 321 previousPos = pos; 322 } 323 } 324 325 protected void checkFinalableFieldType( 326 JavaTerm javaTerm, Set<String> annotationsExclusions, 327 boolean isStatic) 328 throws Exception { 329 330 String javaTermContent = javaTerm.getContent(); 331 332 for (String annotation : annotationsExclusions) { 333 if (javaTermContent.contains( 334 _indent + StringPool.AT + annotation)) { 335 336 return; 337 } 338 } 339 340 StringBundler sb = new StringBundler(4); 341 342 sb.append("(\\b|\\.)"); 343 sb.append(javaTerm.getName()); 344 sb.append(" (=)|(\\+\\+)|(--)|(\\+=)|(-=)|(\\*=)|(/=)|(%=)"); 345 sb.append("|(\\|=)|(&=)|(^=) "); 346 347 Pattern pattern = Pattern.compile(sb.toString()); 348 349 if (!isFinalableField(javaTerm, _name, pattern, true)) { 350 return; 351 } 352 353 String newJavaTermContent = null; 354 355 if (isStatic) { 356 newJavaTermContent = StringUtil.replaceFirst( 357 javaTermContent, "private static ", "private static final "); 358 } 359 else { 360 newJavaTermContent = StringUtil.replaceFirst( 361 javaTermContent, "private ", "private final "); 362 } 363 364 _content = StringUtil.replace( 365 _content, javaTermContent, newJavaTermContent); 366 } 367 368 protected void checkImmutableFieldType(JavaTerm javaTerm) { 369 String oldName = javaTerm.getName(); 370 371 if (oldName.equals("serialVersionUID")) { 372 return; 373 } 374 375 Matcher matcher = _camelCasePattern.matcher(oldName); 376 377 String newName = matcher.replaceAll("$1_$2"); 378 379 newName = StringUtil.toUpperCase(newName); 380 381 if (newName.charAt(0) != CharPool.UNDERLINE) { 382 newName = StringPool.UNDERLINE.concat(newName); 383 } 384 385 _content = _content.replaceAll( 386 "(?<=[\\W&&[^.\"]])(" + oldName + ")\\b", newName); 387 } 388 389 protected void checkJavaFieldType( 390 JavaTerm javaTerm, Set<String> annotationsExclusions, 391 Set<String> immutableFieldTypes) 392 throws Exception { 393 394 if (!BaseSourceProcessor.portalSource || !javaTerm.isVariable()) { 395 return; 396 } 397 398 Pattern pattern = Pattern.compile( 399 "\t(private |protected |public )(static )?(final)?([\\s\\S]*?)" + 400 javaTerm.getName()); 401 402 Matcher matcher = pattern.matcher(javaTerm.getContent()); 403 404 if (!matcher.find()) { 405 return; 406 } 407 408 boolean isFinal = Validator.isNotNull(matcher.group(3)); 409 boolean isStatic = Validator.isNotNull(matcher.group(2)); 410 String javaFieldType = StringUtil.trim(matcher.group(4)); 411 412 if (isFinal && isStatic && javaFieldType.startsWith("Map<")) { 413 checkMutableFieldType(javaTerm); 414 } 415 416 if (!javaTerm.isPrivate()) { 417 return; 418 } 419 420 if (isFinal) { 421 if (immutableFieldTypes.contains(javaFieldType)) { 422 if (isStatic) { 423 checkImmutableFieldType(javaTerm); 424 } 425 else { 426 checkStaticableFieldType(javaTerm); 427 } 428 } 429 } 430 else { 431 checkFinalableFieldType(javaTerm, annotationsExclusions, isStatic); 432 } 433 } 434 435 protected void checkMutableFieldType(JavaTerm javaTerm) { 436 String oldName = javaTerm.getName(); 437 438 String newName = oldName; 439 440 if (newName.charAt(0) != CharPool.UNDERLINE) { 441 newName = StringPool.UNDERLINE.concat(newName); 442 } 443 444 if (StringUtil.isUpperCase(newName)) { 445 StringBundler sb = new StringBundler(newName.length()); 446 447 for (int i = 0; i < newName.length(); i++) { 448 char c = newName.charAt(i); 449 450 if (i > 1) { 451 if (c == CharPool.UNDERLINE) { 452 continue; 453 } 454 455 if (newName.charAt(i - 1) == CharPool.UNDERLINE) { 456 sb.append(c); 457 458 continue; 459 } 460 } 461 462 sb.append(Character.toLowerCase(c)); 463 } 464 465 newName = sb.toString(); 466 } 467 468 469 if (!newName.equals(oldName)) { 470 _content = _content.replaceAll( 471 "(?<=[\\W&&[^.\"]])(" + oldName + ")\\b", newName); 472 } 473 } 474 475 protected void checkStaticableFieldType(JavaTerm javaTerm) { 476 String javaTermContent = javaTerm.getContent(); 477 478 if (!javaTermContent.contains(StringPool.EQUAL)) { 479 return; 480 } 481 482 String newJavaTermContent = StringUtil.replaceFirst( 483 javaTermContent, "private final", "private static final"); 484 485 _content = StringUtil.replace( 486 _content, javaTermContent, newJavaTermContent); 487 } 488 489 protected void checkTestAnnotations(JavaTerm javaTerm) { 490 int methodType = javaTerm.getType(); 491 492 if ((methodType != JavaTerm.TYPE_METHOD_PUBLIC) && 493 (methodType != JavaTerm.TYPE_METHOD_PUBLIC_STATIC)) { 494 495 return; 496 } 497 498 checkAnnotationForMethod( 499 javaTerm, "After", "^.*tearDown\\z", JavaTerm.TYPE_METHOD_PUBLIC, 500 _fileName); 501 checkAnnotationForMethod( 502 javaTerm, "AfterClass", "^.*tearDownClass\\z", 503 JavaTerm.TYPE_METHOD_PUBLIC_STATIC, _fileName); 504 checkAnnotationForMethod( 505 javaTerm, "Before", "^.*setUp\\z", JavaTerm.TYPE_METHOD_PUBLIC, 506 _fileName); 507 checkAnnotationForMethod( 508 javaTerm, "BeforeClass", "^.*setUpClass\\z", 509 JavaTerm.TYPE_METHOD_PUBLIC_STATIC, _fileName); 510 checkAnnotationForMethod( 511 javaTerm, "Test", "^.*test", JavaTerm.TYPE_METHOD_PUBLIC, 512 _fileName); 513 } 514 515 protected void checkUnusedParameters(JavaTerm javaTerm) { 516 if (!javaTerm.isPrivate() || !javaTerm.isMethod()) { 517 return; 518 } 519 520 for (String parameterName : javaTerm.getParameterNames()) { 521 if (StringUtil.count(javaTerm.getContent(), parameterName) == 1) { 522 BaseSourceProcessor.processErrorMessage( 523 _fileName, 524 "Unused parameter " + parameterName + ": " + _fileName + 525 " " + javaTerm.getLineCount()); 526 } 527 } 528 } 529 530 protected void fixJavaTermsDividers( 531 Set<JavaTerm> javaTerms, List<String> javaTermSortExclusions) { 532 533 JavaTerm previousJavaTerm = null; 534 535 Iterator<JavaTerm> itr = javaTerms.iterator(); 536 537 while (itr.hasNext()) { 538 JavaTerm javaTerm = itr.next(); 539 540 if (previousJavaTerm == null) { 541 previousJavaTerm = javaTerm; 542 543 continue; 544 } 545 546 String javaTermContent = javaTerm.getContent(); 547 548 if (javaTermContent.startsWith(_indent + "//")) { 549 previousJavaTerm = javaTerm; 550 551 continue; 552 } 553 554 String previousJavaTermContent = previousJavaTerm.getContent(); 555 556 if (previousJavaTermContent.startsWith(_indent + "//")) { 557 previousJavaTerm = javaTerm; 558 559 continue; 560 } 561 562 String javaTermName = javaTerm.getName(); 563 564 if (BaseSourceProcessor.isExcluded( 565 javaTermSortExclusions, _absolutePath, 566 javaTerm.getLineCount(), javaTermName)) { 567 568 previousJavaTerm = javaTerm; 569 570 continue; 571 } 572 573 String previousJavaTermName = previousJavaTerm.getName(); 574 575 boolean requiresEmptyLine = false; 576 577 if (previousJavaTerm.getType() != javaTerm.getType()) { 578 requiresEmptyLine = true; 579 } 580 else if (!javaTerm.isVariable()) { 581 requiresEmptyLine = true; 582 } 583 else if ((StringUtil.isUpperCase(javaTermName) && 584 !StringUtil.isLowerCase(javaTermName)) || 585 (StringUtil.isUpperCase(previousJavaTermName) && 586 !StringUtil.isLowerCase(previousJavaTermName))) { 587 588 requiresEmptyLine = true; 589 } 590 else if (hasAnnotationCommentOrJavadoc(javaTermContent) || 591 hasAnnotationCommentOrJavadoc(previousJavaTermContent)) { 592 593 requiresEmptyLine = true; 594 } 595 else if ((previousJavaTerm.getType() == 596 JavaTerm.TYPE_VARIABLE_PRIVATE_STATIC) && 597 (previousJavaTermName.equals("_instance") || 598 previousJavaTermName.equals("_log") || 599 previousJavaTermName.equals("_logger"))) { 600 601 requiresEmptyLine = true; 602 } 603 else if (previousJavaTermContent.contains("\n\n\t") || 604 javaTermContent.contains("\n\n\t")) { 605 606 requiresEmptyLine = true; 607 } 608 609 if (requiresEmptyLine) { 610 if (!_content.contains("\n\n" + javaTermContent)) { 611 _content = StringUtil.replace( 612 _content, "\n" + javaTermContent, 613 "\n\n" + javaTermContent); 614 615 return; 616 } 617 } 618 else if (_content.contains("\n\n" + javaTermContent)) { 619 _content = StringUtil.replace( 620 _content, "\n\n" + javaTermContent, "\n" + javaTermContent); 621 622 return; 623 } 624 625 previousJavaTerm = javaTerm; 626 } 627 628 String lastJavaTermContent = previousJavaTerm.getContent(); 629 630 if (!lastJavaTermContent.endsWith("\n\n")) { 631 int x = _content.lastIndexOf(CharPool.CLOSE_CURLY_BRACE); 632 633 _content = StringUtil.insert( 634 _content, "\n", x - _indent.length() + 1); 635 } 636 } 637 638 protected String fixLeadingTabs( 639 String content, String line, int expectedTabCount) { 640 641 int leadingTabCount = JavaSourceProcessor.getLeadingTabCount(line); 642 643 String newLine = line; 644 645 while (leadingTabCount != expectedTabCount) { 646 if (leadingTabCount > expectedTabCount) { 647 newLine = StringUtil.replaceFirst( 648 newLine, StringPool.TAB, StringPool.BLANK); 649 650 leadingTabCount--; 651 } 652 else { 653 newLine = StringPool.TAB + newLine; 654 655 leadingTabCount++; 656 } 657 } 658 659 return StringUtil.replace(content, line, newLine); 660 } 661 662 protected void fixTabsAndIncorrectEmptyLines(JavaTerm javaTerm) { 663 if (!javaTerm.isConstructor() && !javaTerm.isMethod()) { 664 return; 665 } 666 667 String javaTermContent = "\n" + javaTerm.getContent(); 668 669 Pattern methodNameAndParametersPattern = Pattern.compile( 670 "\n" + _indent + "(private |protected |public ).*?(\\{|;)\n", 671 Pattern.DOTALL); 672 673 Matcher matcher = methodNameAndParametersPattern.matcher( 674 javaTermContent); 675 676 if (!matcher.find()) { 677 return; 678 } 679 680 String methodNameAndParameters = matcher.group(); 681 682 String[] lines = StringUtil.splitLines(methodNameAndParameters); 683 684 if (lines.length == 1) { 685 if (methodNameAndParameters.endsWith("{\n") && 686 javaTermContent.contains(methodNameAndParameters + "\n") && 687 !javaTermContent.contains( 688 methodNameAndParameters + "\n" + _indent + StringPool.TAB + 689 "/*") && 690 !javaTermContent.contains( 691 methodNameAndParameters + "\n" + _indent + StringPool.TAB + 692 "// ")) { 693 694 String trimmedJavaTermContent = StringUtil.trimTrailing( 695 javaTermContent); 696 697 if (!trimmedJavaTermContent.endsWith( 698 "\n\n" + _indent + StringPool.CLOSE_CURLY_BRACE)) { 699 700 _content = StringUtil.replace( 701 _content, methodNameAndParameters + "\n", 702 methodNameAndParameters); 703 } 704 } 705 706 return; 707 } 708 709 if (methodNameAndParameters.endsWith("{\n") && 710 !javaTermContent.contains(methodNameAndParameters + "\n") && 711 !javaTermContent.contains( 712 methodNameAndParameters + _indent + 713 StringPool.CLOSE_CURLY_BRACE)) { 714 715 _content = StringUtil.replace( 716 _content, methodNameAndParameters, 717 methodNameAndParameters + "\n"); 718 } 719 720 boolean throwsException = methodNameAndParameters.contains( 721 _indent + "throws "); 722 723 String newMethodNameAndParameters = methodNameAndParameters; 724 725 int expectedTabCount = -1; 726 727 for (int i = 0; i < lines.length; i++) { 728 String line = lines[i]; 729 730 if (line.contains(_indent + "throws ")) { 731 newMethodNameAndParameters = fixLeadingTabs( 732 newMethodNameAndParameters, line, _indent.length() + 1); 733 734 break; 735 } 736 737 if (expectedTabCount == -1) { 738 if (line.endsWith(StringPool.OPEN_PARENTHESIS)) { 739 expectedTabCount = 740 Math.max( 741 JavaSourceProcessor.getLeadingTabCount(line), 742 _indent.length()) + 743 1; 744 745 if (throwsException && 746 (expectedTabCount == (_indent.length() + 1))) { 747 748 expectedTabCount += 1; 749 } 750 } 751 } 752 else { 753 String previousLine = lines[i - 1]; 754 755 if (previousLine.endsWith(StringPool.COMMA) || 756 previousLine.endsWith(StringPool.OPEN_PARENTHESIS)) { 757 758 newMethodNameAndParameters = fixLeadingTabs( 759 newMethodNameAndParameters, line, expectedTabCount); 760 } 761 else { 762 newMethodNameAndParameters = fixLeadingTabs( 763 newMethodNameAndParameters, line, 764 JavaSourceProcessor.getLeadingTabCount(previousLine) + 765 1); 766 } 767 } 768 } 769 770 _content = StringUtil.replace( 771 _content, methodNameAndParameters, newMethodNameAndParameters); 772 } 773 774 protected void formatAnnotations( 775 JavaTerm javaTerm, List<String> testAnnotationsExclusions) 776 throws Exception { 777 778 if ((_indent.length() == 1) && 779 !BaseSourceProcessor.isExcluded( 780 testAnnotationsExclusions, _absolutePath) && 781 _fileName.endsWith("Test.java")) { 782 783 checkTestAnnotations(javaTerm); 784 } 785 786 String javaTermContent = javaTerm.getContent(); 787 788 String newJavaTermContent = JavaSourceProcessor.sortAnnotations( 789 javaTermContent, _indent); 790 791 if (!javaTermContent.equals(newJavaTermContent)) { 792 _content = _content.replace(javaTermContent, newJavaTermContent); 793 } 794 } 795 796 protected String getAccessModifier() { 797 Matcher matcher = _classPattern.matcher(_content); 798 799 if (matcher.find()) { 800 String accessModifier = matcher.group(1); 801 802 if (accessModifier.equals(_ACCESS_MODIFIER_PRIVATE) || 803 accessModifier.equals(_ACCESS_MODIFIER_PROTECTED) || 804 accessModifier.equals(_ACCESS_MODIFIER_PUBLIC)) { 805 806 return accessModifier; 807 } 808 } 809 810 return _ACCESS_MODIFIER_UNKNOWN; 811 } 812 813 protected String getClassName(String line) { 814 int pos = line.indexOf(" extends "); 815 816 if (pos == -1) { 817 pos = line.indexOf(" implements "); 818 } 819 820 if (pos == -1) { 821 pos = line.indexOf(StringPool.OPEN_CURLY_BRACE); 822 } 823 824 if (pos != -1) { 825 line = line.substring(0, pos); 826 } 827 828 pos = line.indexOf(StringPool.LESS_THAN); 829 830 if (pos != -1) { 831 line = line.substring(0, pos); 832 } 833 834 line = line.trim(); 835 836 pos = line.lastIndexOf(StringPool.SPACE); 837 838 return line.substring(pos + 1); 839 } 840 841 protected String getConstructorOrMethodName(String line, int pos) { 842 line = line.substring(0, pos); 843 844 int x = line.lastIndexOf(StringPool.SPACE); 845 846 return line.substring(x + 1); 847 } 848 849 protected JavaTerm getJavaTerm( 850 String name, int type, int lineCount, int startPos, int endPos) 851 throws Exception { 852 853 String javaTermContent = _content.substring(startPos, endPos); 854 855 if (Validator.isNull(name) || !isValidJavaTerm(javaTermContent)) { 856 return null; 857 } 858 859 JavaTerm javaTerm = new JavaTerm( 860 name, type, javaTermContent, lineCount); 861 862 if (javaTerm.isConstructor()) { 863 _constructorCount++; 864 } 865 866 if (!javaTerm.isClass()) { 867 return javaTerm; 868 } 869 870 JavaClass innerClass = new JavaClass( 871 name, _packagePath, _file, _fileName, _absolutePath, 872 javaTermContent, lineCount, _indent + StringPool.TAB, this, 873 _javaTermAccessLevelModifierExclusions); 874 875 _innerClasses.add(innerClass); 876 877 return javaTerm; 878 } 879 880 protected Set<JavaTerm> getJavaTerms() throws Exception { 881 if (_javaTerms != null) { 882 return _javaTerms; 883 } 884 885 Set<JavaTerm> javaTerms = new TreeSet<JavaTerm>( 886 new JavaTermComparator(false)); 887 List<JavaTerm> staticBlocks = new ArrayList<JavaTerm>(); 888 889 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader( 890 new UnsyncStringReader(_content)); 891 892 int index = 0; 893 int lineCount = _lineCount - 1; 894 895 String line = null; 896 897 String javaTermName = null; 898 int javaTermLineCount = -1; 899 int javaTermStartPosition = -1; 900 int javaTermType = -1; 901 902 int lastCommentOrAnnotationPos = -1; 903 904 while ((line = unsyncBufferedReader.readLine()) != null) { 905 lineCount++; 906 907 if (JavaSourceProcessor.getLeadingTabCount(line) != 908 _indent.length()) { 909 910 index = index + line.length() + 1; 911 912 continue; 913 } 914 915 if (line.startsWith(_indent + "private ") || 916 line.equals(_indent + "private") || 917 line.startsWith(_indent + "protected ") || 918 line.equals(_indent + "protected") || 919 line.startsWith(_indent + "public ") || 920 line.equals(_indent + "public") || 921 line.equals(_indent + "static {")) { 922 923 Tuple tuple = getJavaTermTuple(line, _content, index); 924 925 if (tuple == null) { 926 return null; 927 } 928 929 int javaTermEndPosition = 0; 930 931 if (lastCommentOrAnnotationPos == -1) { 932 javaTermEndPosition = index; 933 } 934 else { 935 javaTermEndPosition = lastCommentOrAnnotationPos; 936 } 937 938 if ((javaTermStartPosition != -1) && 939 (javaTermEndPosition < _content.length())) { 940 941 JavaTerm javaTerm = getJavaTerm( 942 javaTermName, javaTermType, javaTermLineCount, 943 javaTermStartPosition, javaTermEndPosition); 944 945 if (javaTerm == null) { 946 return null; 947 } 948 949 if (javaTermType == JavaTerm.TYPE_STATIC_BLOCK) { 950 staticBlocks.add(javaTerm); 951 } 952 else { 953 javaTerms.add(javaTerm); 954 } 955 } 956 957 javaTermLineCount = lineCount; 958 javaTermName = (String)tuple.getObject(0); 959 javaTermStartPosition = javaTermEndPosition; 960 javaTermType = (Integer)tuple.getObject(1); 961 962 lastCommentOrAnnotationPos = -1; 963 } 964 else if (hasAnnotationCommentOrJavadoc(line)) { 965 if (lastCommentOrAnnotationPos == -1) { 966 lastCommentOrAnnotationPos = index; 967 } 968 } 969 else if (!line.startsWith(_indent + StringPool.CLOSE_CURLY_BRACE) && 970 !line.startsWith(_indent + StringPool.CLOSE_PARENTHESIS) && 971 !line.startsWith(_indent + "extends") && 972 !line.startsWith(_indent + "implements") && 973 !BaseSourceProcessor.isExcluded( 974 _javaTermAccessLevelModifierExclusions, _absolutePath, 975 lineCount)) { 976 977 Matcher matcher = _classPattern.matcher(_content); 978 979 if (matcher.find()) { 980 String insideClass = _content.substring(matcher.end()); 981 982 if (insideClass.contains(line)) { 983 BaseSourceProcessor.processErrorMessage( 984 _fileName, 985 "Missing access level modifier: " + _fileName + 986 " " + lineCount); 987 } 988 } 989 } 990 991 index = index + line.length() + 1; 992 } 993 994 if (javaTermStartPosition != -1) { 995 int javaTermEndPosition = 996 _content.lastIndexOf(StringPool.CLOSE_CURLY_BRACE) - 997 _indent.length() + 1; 998 999 JavaTerm javaTerm = getJavaTerm( 1000 javaTermName, javaTermType, javaTermLineCount, 1001 javaTermStartPosition, javaTermEndPosition); 1002 1003 if (javaTerm == null) { 1004 return null; 1005 } 1006 1007 if (javaTermType == JavaTerm.TYPE_STATIC_BLOCK) { 1008 staticBlocks.add(javaTerm); 1009 } 1010 else { 1011 javaTerms.add(javaTerm); 1012 } 1013 } 1014 1015 _javaTerms = addStaticBlocks(javaTerms, staticBlocks); 1016 1017 return _javaTerms; 1018 } 1019 1020 protected Tuple getJavaTermTuple(String line, String accessModifier) { 1021 if (!line.startsWith(_indent + accessModifier + StringPool.SPACE)) { 1022 return null; 1023 } 1024 1025 int x = line.indexOf(StringPool.EQUAL); 1026 int y = line.indexOf(StringPool.OPEN_PARENTHESIS); 1027 1028 if (line.startsWith(_indent + accessModifier + " static ")) { 1029 if (line.contains(" class ") || line.contains(" enum ")) { 1030 return getJavaTermTuple( 1031 getClassName(line), accessModifier, 1032 JavaTerm.TYPE_CLASS_PRIVATE_STATIC, 1033 JavaTerm.TYPE_CLASS_PROTECTED_STATIC, 1034 JavaTerm.TYPE_CLASS_PUBLIC_STATIC); 1035 } 1036 1037 if (((x > 0) && ((y == -1) || (y > x))) || 1038 (line.endsWith(StringPool.SEMICOLON) && (y == -1))) { 1039 1040 return getJavaTermTuple( 1041 getVariableName(line), accessModifier, 1042 JavaTerm.TYPE_VARIABLE_PRIVATE_STATIC, 1043 JavaTerm.TYPE_VARIABLE_PROTECTED_STATIC, 1044 JavaTerm.TYPE_VARIABLE_PUBLIC_STATIC); 1045 } 1046 1047 if (y != -1) { 1048 return getJavaTermTuple( 1049 getConstructorOrMethodName(line, y), accessModifier, 1050 JavaTerm.TYPE_METHOD_PRIVATE_STATIC, 1051 JavaTerm.TYPE_METHOD_PROTECTED_STATIC, 1052 JavaTerm.TYPE_METHOD_PUBLIC_STATIC); 1053 } 1054 1055 return null; 1056 } 1057 1058 if (line.contains(" @interface ") || line.contains(" class ") || 1059 line.contains(" enum ") || line.contains(" interface ")) { 1060 1061 return getJavaTermTuple( 1062 getClassName(line), accessModifier, JavaTerm.TYPE_CLASS_PRIVATE, 1063 JavaTerm.TYPE_CLASS_PROTECTED, JavaTerm.TYPE_CLASS_PUBLIC); 1064 } 1065 1066 if (((x > 0) && ((y == -1) || (y > x))) || 1067 (line.endsWith(StringPool.SEMICOLON) && (y == -1))) { 1068 1069 return getJavaTermTuple( 1070 getVariableName(line), accessModifier, 1071 JavaTerm.TYPE_VARIABLE_PRIVATE, 1072 JavaTerm.TYPE_VARIABLE_PROTECTED, 1073 JavaTerm.TYPE_VARIABLE_PUBLIC); 1074 } 1075 1076 if (y != -1) { 1077 int spaceCount = StringUtil.count( 1078 line.substring(0, y), StringPool.SPACE); 1079 1080 if (spaceCount == 1) { 1081 return getJavaTermTuple( 1082 getConstructorOrMethodName(line, y), accessModifier, 1083 JavaTerm.TYPE_CONSTRUCTOR_PRIVATE, 1084 JavaTerm.TYPE_CONSTRUCTOR_PROTECTED, 1085 JavaTerm.TYPE_CONSTRUCTOR_PUBLIC); 1086 } 1087 1088 if (spaceCount > 1) { 1089 return getJavaTermTuple( 1090 getConstructorOrMethodName(line, y), accessModifier, 1091 JavaTerm.TYPE_METHOD_PRIVATE, 1092 JavaTerm.TYPE_METHOD_PROTECTED, 1093 JavaTerm.TYPE_METHOD_PUBLIC); 1094 } 1095 } 1096 1097 return null; 1098 } 1099 1100 protected Tuple getJavaTermTuple(String line, String content, int index) { 1101 int posStartNextLine = index; 1102 1103 while (!line.endsWith(StringPool.OPEN_CURLY_BRACE) && 1104 !line.endsWith(StringPool.SEMICOLON)) { 1105 1106 posStartNextLine = 1107 content.indexOf(StringPool.NEW_LINE, posStartNextLine) + 1; 1108 1109 int posEndNextline = content.indexOf( 1110 StringPool.NEW_LINE, posStartNextLine); 1111 1112 String nextLine = content.substring( 1113 posStartNextLine, posEndNextline); 1114 1115 nextLine = StringUtil.trimLeading(nextLine); 1116 1117 if (line.endsWith(StringPool.OPEN_PARENTHESIS)) { 1118 line += nextLine; 1119 } 1120 else { 1121 line += StringPool.SPACE + nextLine; 1122 } 1123 } 1124 1125 line = StringUtil.replace(line, " synchronized " , StringPool.SPACE); 1126 1127 for (String accessModifier : _ACCESS_MODIFIERS) { 1128 Tuple tuple = getJavaTermTuple(line, accessModifier); 1129 1130 if (tuple != null) { 1131 return tuple; 1132 } 1133 } 1134 1135 if (line.startsWith(_indent + "static {")) { 1136 return new Tuple("static", JavaTerm.TYPE_STATIC_BLOCK); 1137 } 1138 1139 return null; 1140 } 1141 1142 protected Tuple getJavaTermTuple( 1143 String javaTermName, String accessModifier, int privateJavaTermType, 1144 int protectedJavaTermType, int publicJavaTermType) { 1145 1146 if (accessModifier.equals(_ACCESS_MODIFIER_PRIVATE)) { 1147 return new Tuple(javaTermName, privateJavaTermType); 1148 } 1149 1150 if (accessModifier.equals(_ACCESS_MODIFIER_PROTECTED)) { 1151 return new Tuple(javaTermName, protectedJavaTermType); 1152 } 1153 1154 return new Tuple(javaTermName, publicJavaTermType); 1155 } 1156 1157 protected String getVariableName(String line) { 1158 int x = line.indexOf(StringPool.EQUAL); 1159 int y = line.lastIndexOf(StringPool.SPACE); 1160 1161 if (x != -1) { 1162 line = line.substring(0, x); 1163 line = StringUtil.trim(line); 1164 1165 y = line.lastIndexOf(StringPool.SPACE); 1166 1167 return line.substring(y + 1); 1168 } 1169 1170 if (line.endsWith(StringPool.SEMICOLON)) { 1171 return line.substring(y + 1, line.length() - 1); 1172 } 1173 1174 return StringPool.BLANK; 1175 } 1176 1177 protected boolean hasAnnotationCommentOrJavadoc(String s) { 1178 if (s.startsWith(_indent + StringPool.AT) || 1179 s.startsWith(_indent + StringPool.SLASH) || 1180 s.startsWith(_indent + " *")) { 1181 1182 return true; 1183 } 1184 else { 1185 return false; 1186 } 1187 } 1188 1189 protected boolean isFinalableField( 1190 JavaTerm javaTerm, String javaTermClassName, Pattern pattern, 1191 boolean checkOuterClass) { 1192 1193 if (checkOuterClass && (_outerClass != null)) { 1194 return _outerClass.isFinalableField( 1195 javaTerm, javaTermClassName, pattern, true); 1196 } 1197 1198 for (JavaTerm curJavaTerm : _javaTerms) { 1199 if (!curJavaTerm.isMethod() && 1200 (!curJavaTerm.isConstructor() || 1201 javaTermClassName.equals(_name))) { 1202 1203 continue; 1204 } 1205 1206 Matcher matcher = pattern.matcher(curJavaTerm.getContent()); 1207 1208 if (matcher.find()) { 1209 return false; 1210 } 1211 } 1212 1213 for (JavaClass innerClass : _innerClasses) { 1214 if (!innerClass.isFinalableField( 1215 javaTerm, javaTermClassName, pattern, false)) { 1216 1217 return false; 1218 } 1219 } 1220 1221 return true; 1222 } 1223 1224 protected boolean isValidJavaTerm(String content) { 1225 if (content.startsWith(_indent + "static {")) { 1226 return true; 1227 } 1228 1229 while (!content.startsWith(_indent + "private") && 1230 !content.startsWith(_indent + "protected") && 1231 !content.startsWith(_indent + "public")) { 1232 1233 content = content.substring(content.indexOf("\n") + 1); 1234 } 1235 1236 int indentLinesCount = 1237 StringUtil.count(content, "\n" + _indent) - 1238 StringUtil.count(content, "\n" + _indent + StringPool.TAB); 1239 1240 content = StringUtil.trim(content); 1241 1242 if (content.endsWith(StringPool.CLOSE_CURLY_BRACE) && 1243 ((indentLinesCount == 1) || 1244 (((indentLinesCount == 2) || (indentLinesCount == 3)) && 1245 content.contains("\n" + _indent + "static {")))) { 1246 1247 return true; 1248 } 1249 else if ((content.endsWith("};") && (indentLinesCount == 1)) || 1250 (content.endsWith(StringPool.SEMICOLON) && 1251 (indentLinesCount == 0))) { 1252 1253 return true; 1254 } 1255 1256 return false; 1257 } 1258 1259 protected void sortJavaTerms( 1260 JavaTerm previousJavaTerm, JavaTerm javaTerm, 1261 List<String> javaTermSortExclusions) { 1262 1263 if (previousJavaTerm == null) { 1264 return; 1265 } 1266 1267 String javaTermName = javaTerm.getName(); 1268 1269 if (BaseSourceProcessor.isExcluded( 1270 javaTermSortExclusions, _absolutePath, -1, javaTermName)) { 1271 1272 return; 1273 } 1274 1275 if (previousJavaTerm.getLineCount() <= javaTerm.getLineCount()) { 1276 return; 1277 } 1278 1279 String previousJavaTermName = previousJavaTerm.getName(); 1280 1281 String javaTermNameLowerCase = StringUtil.toLowerCase(javaTermName); 1282 String previousJavaTermNameLowerCase = StringUtil.toLowerCase( 1283 previousJavaTermName); 1284 1285 if (_fileName.contains("persistence") && 1286 ((previousJavaTermName.startsWith("doCount") && 1287 javaTermName.startsWith("doCount")) || 1288 (previousJavaTermName.startsWith("doFind") && 1289 javaTermName.startsWith("doFind")) || 1290 (previousJavaTermNameLowerCase.startsWith("count") && 1291 javaTermNameLowerCase.startsWith("count")) || 1292 (previousJavaTermNameLowerCase.startsWith("filter") && 1293 javaTermNameLowerCase.startsWith("filter")) || 1294 (previousJavaTermNameLowerCase.startsWith("find") && 1295 javaTermNameLowerCase.startsWith("find")) || 1296 (previousJavaTermNameLowerCase.startsWith("join") && 1297 javaTermNameLowerCase.startsWith("join")))) { 1298 } 1299 else { 1300 _content = StringUtil.replaceFirst( 1301 _content, "\n" + javaTerm.getContent(), 1302 "\n" + previousJavaTerm.getContent()); 1303 _content = StringUtil.replaceLast( 1304 _content, "\n" + previousJavaTerm.getContent(), 1305 "\n" + javaTerm.getContent()); 1306 } 1307 } 1308 1309 private static final String _ACCESS_MODIFIER_PRIVATE = "private"; 1310 1311 private static final String _ACCESS_MODIFIER_PROTECTED = "protected"; 1312 1313 private static final String _ACCESS_MODIFIER_PUBLIC = "public"; 1314 1315 private static final String _ACCESS_MODIFIER_UNKNOWN = "unknown"; 1316 1317 private static final String[] _ACCESS_MODIFIERS = { 1318 _ACCESS_MODIFIER_PRIVATE, _ACCESS_MODIFIER_PROTECTED, 1319 _ACCESS_MODIFIER_PUBLIC 1320 }; 1321 1322 private String _absolutePath; 1323 private Pattern _camelCasePattern = Pattern.compile("([a-z])([A-Z0-9])"); 1324 private Pattern _classPattern = Pattern.compile( 1325 "(private |protected |public )(static )*class ([\\s\\S]*?) \\{\n"); 1326 private int _constructorCount = 0; 1327 private String _content; 1328 private File _file; 1329 private String _fileName; 1330 private String _indent; 1331 private List<JavaClass> _innerClasses = new ArrayList<JavaClass>(); 1332 private List<String> _javaTermAccessLevelModifierExclusions; 1333 private Set<JavaTerm> _javaTerms; 1334 private int _lineCount; 1335 private String _name; 1336 private JavaClass _outerClass; 1337 private String _packagePath; 1338 1339 }