Coverage Report - org.codehaus.plexus.compiler.ajc.AspectJCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
AspectJCompiler
65%
86/132
42%
43/102
7,889
AspectJCompiler$AspectJMessagePrinter
100%
2/2
N/A
7,889
 
 1  
 package org.codehaus.plexus.compiler.ajc;
 2  
 
 3  
 import org.aspectj.ajdt.ajc.BuildArgParser;
 4  
 import org.aspectj.ajdt.internal.core.builder.AjBuildConfig;
 5  
 import org.aspectj.ajdt.internal.core.builder.AjBuildManager;
 6  
 import org.aspectj.bridge.AbortException;
 7  
 import org.aspectj.bridge.IMessage;
 8  
 import org.aspectj.bridge.ISourceLocation;
 9  
 import org.aspectj.bridge.MessageHandler;
 10  
 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 11  
 import org.aspectj.tools.ajc.Main;
 12  
 import org.codehaus.plexus.compiler.AbstractCompiler;
 13  
 import org.codehaus.plexus.compiler.CompilerConfiguration;
 14  
 import org.codehaus.plexus.compiler.CompilerException;
 15  
 import org.codehaus.plexus.compiler.CompilerMessage;
 16  
 import org.codehaus.plexus.compiler.CompilerOutputStyle;
 17  
 import org.codehaus.plexus.compiler.CompilerResult;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.IOException;
 21  
 import java.net.MalformedURLException;
 22  
 import java.net.URL;
 23  
 import java.net.URLClassLoader;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Arrays;
 26  
 import java.util.LinkedList;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 
 30  
 /**
 31  
  * <p/>
 32  
  * Options
 33  
  * <p/>
 34  
  * -injars JarList
 35  
  * <p/>
 36  
  * Accept as source bytecode any .class files inside the specified .jar files. The output will include these
 37  
  * classes, possibly as woven with any applicable aspects. JarList, like classpath, is a single argument
 38  
  * containing a list of paths to jar files, delimited by the platform- specific classpath delimiter.
 39  
  * <p/>
 40  
  * -aspectpath JarList
 41  
  * <p/>
 42  
  * Weave binary aspects from JarList zip files into all sources. The aspects should have been output by
 43  
  * the same version of the compiler. To run the output classes requires putting all the aspectpath entries on
 44  
  * the run classpath. JarList, like classpath, is a single argument containing a list of paths to jar files,
 45  
  * delimited by the platform- specific classpath delimiter.
 46  
  * <p/>
 47  
  * -argfile File
 48  
  * <p/>
 49  
  * The file is a line-delimited list of arguments. These arguments are inserted into the argument list.
 50  
  * <p/>
 51  
  * -outjar output.jar
 52  
  * <p/>
 53  
  * Put output classes in zip file output.jar.
 54  
  * <p/>
 55  
  * -incremental
 56  
  * <p/>
 57  
  * Run the compiler continuously. After the initial compilation, the compiler will wait to recompile until it
 58  
  * reads a newline from the standard input, and will quit when it reads a 'q'. It will only recompile necessary
 59  
  * components, so a recompile should be much faster than doing a second compile. This requires -sourceroots.
 60  
  * <p/>
 61  
  * -sourceroots DirPaths
 62  
  * <p/>
 63  
  * Find and build all .java or .aj source files under any directory listed in DirPaths. DirPaths, like
 64  
  * classpath, is a single argument containing a list of paths to directories, delimited by the platform-
 65  
  * specific classpath delimiter. Required by -incremental.
 66  
  * <p/>
 67  
  * -emacssym
 68  
  * <p/>
 69  
  * Generate .ajesym symbol files for emacs support
 70  
  * <p/>
 71  
  * -Xlint
 72  
  * <p/>
 73  
  * Same as -Xlint:warning (enabled by default)
 74  
  * <p/>
 75  
  * -Xlint:{level}
 76  
  * <p/>
 77  
  * Set default level for messages about potential programming mistakes in crosscutting code. {level} may be
 78  
  * ignore, warning, or error. This overrides entries in org/aspectj/weaver/XlintDefault.properties from
 79  
  * aspectjtools.jar, but does not override levels set using the -Xlintfile option.
 80  
  * <p/>
 81  
  * -Xlintfile PropertyFile
 82  
  * <p/>
 83  
  * Specify properties file to set levels for specific crosscutting messages. PropertyFile is a path to a
 84  
  * Java .properties file that takes the same property names and values as
 85  
  * org/aspectj/weaver/XlintDefault.properties from aspectjtools.jar, which it also overrides.
 86  
  * -help
 87  
  * <p/>
 88  
  * Emit information on compiler options and usage
 89  
  * <p/>
 90  
  * -version
 91  
  * <p/>
 92  
  * Emit the version of the AspectJ compiler
 93  
  * <p/>
 94  
  * -classpath Path
 95  
  * <p/>
 96  
  * Specify where to find user class files. Path is a single argument containing a list of paths to zip files
 97  
  * or directories, delimited by the platform-specific path delimiter.
 98  
  * <p/>
 99  
  * -bootclasspath Path
 100  
  * <p/>
 101  
  * Override location of VM's bootclasspath for purposes of evaluating types when compiling. Path is a single
 102  
  * argument containing a list of paths to zip files or directories, delimited by the platform-specific path
 103  
  * delimiter.
 104  
  * <p/>
 105  
  * -extdirs Path
 106  
  * <p/>
 107  
  * Override location of VM's extension directories for purposes of evaluating types when compiling. Path is
 108  
  * a single argument containing a list of paths to directories, delimited by the platform-specific path
 109  
  * delimiter.
 110  
  * <p/>
 111  
  * -d Directory
 112  
  * <p/>
 113  
  * Specify where to place generated .class files. If not specified, Directory defaults to the current
 114  
  * working dir.
 115  
  * <p/>
 116  
  * -target [1.1|1.2]
 117  
  * <p/>
 118  
  * Specify classfile target setting (1.1 or 1.2, default is 1.1)
 119  
  * <p/>
 120  
  * -1.3
 121  
  * <p/>
 122  
  * Set compliance level to 1.3 (default)
 123  
  * -1.4
 124  
  * <p/>
 125  
  * Set compliance level to 1.4
 126  
  * -source [1.3|1.4]
 127  
  * <p/>
 128  
  * Toggle assertions (1.3 or 1.4, default is 1.3 in -1.3 mode and 1.4 in -1.4 mode). When using -source 1.3,
 129  
  * an assert() statement valid under Java 1.4 will result in a compiler error. When using -source 1.4, treat
 130  
  * assert as a keyword and implement assertions according to the 1.4 language spec.
 131  
  * <p/>
 132  
  * -nowarn
 133  
  * <p/>
 134  
  * Emit no warnings (equivalent to '-warn:none') This does not suppress messages generated by declare warning
 135  
  * or Xlint.
 136  
  * <p/>
 137  
  * -warn: items
 138  
  * <p/>
 139  
  * Emit warnings for any instances of the comma-delimited list of questionable code
 140  
  * (eg '-warn:unusedLocals,deprecation'):
 141  
  * <p/>
 142  
  * constructorName        method with constructor name
 143  
  * packageDefaultMethod   attempt to override package-default method
 144  
  * deprecation            usage of deprecated type or member
 145  
  * maskedCatchBlocks      hidden catch block
 146  
  * unusedLocals           local variable never read
 147  
  * unusedArguments        method argument never read
 148  
  * unusedImports          import statement not used by code in file
 149  
  * none                   suppress all compiler warnings
 150  
  * <p/>
 151  
  * <p/>
 152  
  * -warn:none does not suppress messages generated by declare warning or Xlint.
 153  
  * <p/>
 154  
  * -deprecation
 155  
  * <p/>
 156  
  * Same as -warn:deprecation
 157  
  * <p/>
 158  
  * -noImportError
 159  
  * <p/>
 160  
  * Emit no errors for unresolved imports
 161  
  * <p/>
 162  
  * -proceedOnError
 163  
  * <p/>
 164  
  * Keep compiling after error, dumping class files with problem methods
 165  
  * <p/>
 166  
  * -g:[lines,vars,source]
 167  
  * <p/>
 168  
  * debug attributes level, that may take three forms:
 169  
  * <p/>
 170  
  * -g         all debug info ('-g:lines,vars,source')
 171  
  * -g:none    no debug info
 172  
  * -g:{items} debug info for any/all of [lines, vars, source], e.g.,
 173  
  * -g:lines,source
 174  
  * <p/>
 175  
  * <p/>
 176  
  * -preserveAllLocals
 177  
  * <p/>
 178  
  * Preserve all local variables during code generation (to facilitate debugging).
 179  
  * <p/>
 180  
  * -referenceInfo
 181  
  * <p/>
 182  
  * Compute reference information.
 183  
  * <p/>
 184  
  * -encoding format
 185  
  * <p/>
 186  
  * Specify default source encoding format. Specify custom encoding on a per file basis by suffixing each
 187  
  * input source file/folder name with '[encoding]'.
 188  
  * <p/>
 189  
  * -verbose
 190  
  * <p/>
 191  
  * Emit messages about accessed/processed compilation units
 192  
  * <p/>
 193  
  * -log file
 194  
  * <p/>
 195  
  * Specify a log file for compiler messages.
 196  
  * -progress
 197  
  * <p/>
 198  
  * Show progress (requires -log mode).
 199  
  * -time
 200  
  * <p/>
 201  
  * Display speed information.
 202  
  * -noExit
 203  
  * <p/>
 204  
  * Do not call System.exit(n) at end of compilation (n=0 if no error)
 205  
  * -repeat N
 206  
  * <p/>
 207  
  * Repeat compilation process N times (typically to do performance analysis).
 208  
  * -Xnoweave
 209  
  * <p/>
 210  
  * (Experimental) produce unwoven class files for input using -injars.
 211  
  * -Xnoinline
 212  
  * <p/>
 213  
  * (Experimental) do not inline around advice
 214  
  * -XincrementalFile file
 215  
  * <p/>
 216  
  * (Experimental) This works like incremental mode, but using a file rather than standard input to control
 217  
  * the compiler. It will recompile each time file is changed and and halt when file is deleted.
 218  
  * <p/>
 219  
  * -XserializableAspects
 220  
  * <p/>
 221  
  * (Experimental) Normally it is an error to declare aspects Serializable. This option removes that restriction.
 222  
  *
 223  
  * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
 224  
  * @plexus.component role="org.codehaus.plexus.compiler.Compiler" role-hint="aspectj"
 225  
  */
 226  
 public class AspectJCompiler
 227  
     extends AbstractCompiler
 228  
 {
 229  
 
 230  
     // ----------------------------------------------------------------------
 231  
     //
 232  
     // ----------------------------------------------------------------------
 233  
 
 234  
     public AspectJCompiler()
 235  
     {
 236  1
         super( CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE, ".java", ".class", null );
 237  1
     }
 238  
 
 239  
     public CompilerResult performCompile( CompilerConfiguration config )
 240  
         throws CompilerException
 241  
     {
 242  3
         File destinationDir = new File( config.getOutputLocation() );
 243  
 
 244  3
         if ( !destinationDir.exists() )
 245  
         {
 246  3
             destinationDir.mkdirs();
 247  
         }
 248  
 
 249  3
         String[] sourceFiles = getSourceFiles( config );
 250  
 
 251  3
         if ( sourceFiles.length == 0 )
 252  
         {
 253  0
             return new CompilerResult();
 254  
         }
 255  
 
 256  6
         System.out.println(
 257  
             "Compiling " + sourceFiles.length + " " + "source file" + ( sourceFiles.length == 1 ? "" : "s" ) + " to "
 258  3
                 + destinationDir.getAbsolutePath() );
 259  
 
 260  
         //        String[] args = buildCompilerArguments( config, sourceFiles );
 261  3
         AjBuildConfig buildConfig = buildCompilerConfig( config );
 262  3
         return new CompilerResult().compilerMessages( compileInProcess( buildConfig ) );
 263  
     }
 264  
 
 265  
     private static class AspectJMessagePrinter extends Main.MessagePrinter
 266  
     {
 267  
         public AspectJMessagePrinter( boolean verbose )
 268  
         {
 269  3
             super( verbose );
 270  3
         }
 271  
     }
 272  
 
 273  
     private AjBuildConfig buildCompilerConfig( CompilerConfiguration config )
 274  
         throws CompilerException
 275  
     {
 276  3
         AjBuildConfig buildConfig = new AjBuildConfig(new BuildArgParser(new AspectJMessagePrinter(config.isVerbose())));
 277  3
         buildConfig.setIncrementalMode( false );
 278  
 
 279  3
         String[] files = getSourceFiles( config );
 280  3
         if ( files != null )
 281  
         {
 282  3
             buildConfig.setFiles( buildFileList( Arrays.asList( files ) ) );
 283  
         }
 284  
 
 285  3
         setSourceVersion( buildConfig, config.getSourceVersion() );
 286  
 
 287  3
         if ( config.isDebug() )
 288  
         {
 289  0
             buildConfig.getOptions().produceDebugAttributes =
 290  
                 ClassFileConstants.ATTR_SOURCE + ClassFileConstants.ATTR_LINES + ClassFileConstants.ATTR_VARS;
 291  
         }
 292  
 
 293  3
         Map<String, String> javaOpts = config.getCustomCompilerArguments();
 294  3
         if ( javaOpts != null && !javaOpts.isEmpty() )
 295  
         {
 296  
             // TODO support customCompilerArguments
 297  
             // buildConfig.setJavaOptions( javaOpts );
 298  
         }
 299  
 
 300  3
         List<String> cp = new LinkedList<String>( config.getClasspathEntries() );
 301  
 
 302  3
         File javaHomeDir = new File( System.getProperty( "java.home" ) );
 303  3
         File[] jars = new File( javaHomeDir, "lib" ).listFiles();
 304  3
         if ( jars != null )
 305  
         {
 306  123
             for ( File jar : jars )
 307  
             {
 308  120
                 if ( jar.getName().endsWith( ".jar" ) || jar.getName().endsWith( ".zip" ) )
 309  
                 {
 310  33
                     cp.add( 0, jar.getAbsolutePath() );
 311  
                 }
 312  
             }
 313  
         }
 314  3
         jars = new File( javaHomeDir, "../Classes" ).listFiles();
 315  3
         if ( jars != null )
 316  
         {
 317  0
             for ( File jar : jars )
 318  
             {
 319  0
                 if ( jar.getName().endsWith( ".jar" ) || jar.getName().endsWith( ".zip" ) )
 320  
                 {
 321  0
                     cp.add( 0, jar.getAbsolutePath() );
 322  
                 }
 323  
             }
 324  
         }
 325  
 
 326  3
         checkForAspectJRT( cp );
 327  3
         if ( cp != null && !cp.isEmpty() )
 328  
         {
 329  3
             List<String> elements = new ArrayList<String>( cp.size() );
 330  3
             for ( String path : cp )
 331  
             {
 332  39
                 elements.add( ( new File( path ) ).getAbsolutePath() );
 333  39
             }
 334  
 
 335  3
             buildConfig.setClasspath( elements );
 336  
         }
 337  
 
 338  3
         String outputLocation = config.getOutputLocation();
 339  3
         if ( outputLocation != null )
 340  
         {
 341  3
             File outDir = new File( outputLocation );
 342  3
             if ( !outDir.exists() )
 343  
             {
 344  0
                 outDir.mkdirs();
 345  
             }
 346  
 
 347  3
             buildConfig.setOutputDir( outDir );
 348  
         }
 349  
 
 350  3
         if ( config instanceof AspectJCompilerConfiguration )
 351  
         {
 352  0
             AspectJCompilerConfiguration ajCfg = (AspectJCompilerConfiguration) config;
 353  
 
 354  0
             Map<String, File> sourcePathResources = ajCfg.getSourcePathResources();
 355  0
             if ( sourcePathResources != null && !sourcePathResources.isEmpty() )
 356  
             {
 357  0
                 buildConfig.setSourcePathResources( sourcePathResources );
 358  
             }
 359  
 
 360  0
             Map<String, String> ajOptions = ajCfg.getAJOptions();
 361  0
             if ( ajOptions != null && !ajOptions.isEmpty() )
 362  
             {
 363  
                 // TODO not supported
 364  
                 //buildConfig.setAjOptions( ajCfg.getAJOptions() );
 365  
             }
 366  
 
 367  0
             List<File> aspectPath = buildFileList( ajCfg.getAspectPath() );
 368  0
             if ( aspectPath != null && !aspectPath.isEmpty() )
 369  
             {
 370  0
                 buildConfig.setAspectpath( buildFileList( ajCfg.getAspectPath() ) );
 371  
             }
 372  
 
 373  0
             List<File> inJars = buildFileList( ajCfg.getInJars() );
 374  0
             if ( inJars != null && !inJars.isEmpty() )
 375  
             {
 376  0
                 buildConfig.setInJars( buildFileList( ajCfg.getInJars() ) );
 377  
             }
 378  
 
 379  0
             List<File> inPaths = buildFileList( ajCfg.getInPath() );
 380  0
             if ( inPaths != null && !inPaths.isEmpty() )
 381  
             {
 382  0
                 buildConfig.setInPath( buildFileList( ajCfg.getInPath() ) );
 383  
             }
 384  
 
 385  0
             String outJar = ajCfg.getOutputJar();
 386  0
             if ( outJar != null )
 387  
             {
 388  0
                 buildConfig.setOutputJar( new File( ajCfg.getOutputJar() ) );
 389  
             }
 390  
         }
 391  
 
 392  3
         return buildConfig;
 393  
     }
 394  
 
 395  
     private List<CompilerMessage> compileInProcess( AjBuildConfig buildConfig )
 396  
         throws CompilerException
 397  
     {
 398  
 
 399  3
         MessageHandler messageHandler = new MessageHandler();
 400  
 
 401  3
         AjBuildManager manager = new AjBuildManager( messageHandler );
 402  
 
 403  
         try
 404  
         {
 405  3
             manager.batchBuild( buildConfig, messageHandler );
 406  
         }
 407  0
         catch ( AbortException e )
 408  
         {
 409  0
             throw new CompilerException( "Unknown error while compiling", e );
 410  
         }
 411  0
         catch ( IOException e )
 412  
         {
 413  0
             throw new CompilerException( "Unknown error while compiling", e );
 414  3
         }
 415  
 
 416  
         // We need the location of the maven so we have a couple of options
 417  
         // here.
 418  
         //
 419  
         // The aspectjrt jar is something this component needs to function so we
 420  
         // can either
 421  
         // bake it into the plugin and retrieve it somehow or use a system
 422  
         // property or we
 423  
         // could pass in a set of parameters in a Map.
 424  
 
 425  3
         boolean errors = messageHandler.hasAnyMessage( IMessage.ERROR, true );
 426  
 
 427  3
         List<CompilerMessage> messages = new ArrayList<CompilerMessage>();
 428  3
         if ( errors )
 429  
         {
 430  1
             IMessage[] errorMessages = messageHandler.getMessages( IMessage.ERROR, true );
 431  
 
 432  2
             for ( IMessage m : errorMessages )
 433  
             {
 434  1
                 ISourceLocation sourceLocation = m.getSourceLocation();
 435  
                 CompilerMessage error;
 436  
 
 437  1
                 if ( sourceLocation == null )
 438  
                 {
 439  0
                     error = new CompilerMessage( m.getMessage(), true );
 440  
                 }
 441  
                 else
 442  
                 {
 443  1
                     error =
 444  1
                         new CompilerMessage( sourceLocation.getSourceFile().getPath(), true, sourceLocation.getLine(),
 445  1
                                              sourceLocation.getColumn(), sourceLocation.getEndLine(),
 446  1
                                              sourceLocation.getColumn(), m.getMessage() );
 447  
                 }
 448  1
                 messages.add( error );
 449  
             }
 450  
         }
 451  
 
 452  3
         return messages;
 453  
     }
 454  
 
 455  
     private void checkForAspectJRT( List<String> cp )
 456  
     {
 457  3
         if ( cp == null || cp.isEmpty() )
 458  
         {
 459  0
             throw new IllegalStateException( "AspectJ Runtime not found in supplied classpath" );
 460  
         }
 461  
         else
 462  
         {
 463  
             try
 464  
             {
 465  3
                 URL[] urls = new URL[cp.size()];
 466  42
                 for ( int i = 0; i < urls.length; i++ )
 467  
                 {
 468  39
                     urls[i] = ( new File( cp.get( i ) ) ).toURL();
 469  
                 }
 470  
 
 471  3
                 URLClassLoader cloader = new URLClassLoader( urls );
 472  
 
 473  3
                 cloader.loadClass( "org.aspectj.lang.JoinPoint" );
 474  
             }
 475  0
             catch ( MalformedURLException e )
 476  
             {
 477  0
                 throw new IllegalArgumentException( "Invalid classpath entry" );
 478  
             }
 479  0
             catch ( ClassNotFoundException e )
 480  
             {
 481  0
                 throw new IllegalStateException( "AspectJ Runtime not found in supplied classpath" );
 482  3
             }
 483  
         }
 484  3
     }
 485  
 
 486  
     private List<File> buildFileList( List<String> locations )
 487  
     {
 488  3
         List<File> fileList = new LinkedList<File>();
 489  3
         for ( String location : locations )
 490  
         {
 491  3
             fileList.add( new File( location ) );
 492  3
         }
 493  
 
 494  3
         return fileList;
 495  
     }
 496  
 
 497  
     /**
 498  
      * Set the source version in ajc compiler
 499  
      *
 500  
      * @param buildConfig
 501  
      * @param sourceVersion
 502  
      */
 503  
     private void setSourceVersion( AjBuildConfig buildConfig, String sourceVersion )
 504  
         throws CompilerException
 505  
     {
 506  3
         if ( "1.9".equals( sourceVersion ) )
 507  
         {
 508  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_9;
 509  
         }
 510  3
         else if ( "1.8".equals( sourceVersion ) )
 511  
         {
 512  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_8;
 513  
         }
 514  3
         else if ( "1.7".equals( sourceVersion ) )
 515  
         {
 516  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_7;
 517  
         }
 518  3
         else if ( "1.6".equals( sourceVersion ) )
 519  
         {
 520  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_6;
 521  
         }
 522  3
         else if ( "1.5".equals( sourceVersion ) )
 523  
         {
 524  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_5;
 525  
         }
 526  3
         else if ( "5.0".equals( sourceVersion ) )
 527  
         {
 528  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_5;
 529  
         }
 530  3
         else if ( "1.4".equals( sourceVersion ) )
 531  
         {
 532  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_4;
 533  
         }
 534  3
         else if ( "1.3".equals( sourceVersion ) )
 535  
         {
 536  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_3;
 537  
         }
 538  3
         else if ( "1.2".equals( sourceVersion ) )
 539  
         {
 540  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_2;
 541  
         }
 542  3
         else if ( "1.1".equals( sourceVersion ) )
 543  
         {
 544  0
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_1;
 545  
         }
 546  3
         else if ( sourceVersion == null || sourceVersion.length() <= 0 )
 547  
         {
 548  3
             buildConfig.getOptions().sourceLevel = ClassFileConstants.JDK1_3;
 549  
         }
 550  
         else
 551  
         {
 552  0
             throw new CompilerException( "The source version was not recognized: " + sourceVersion );
 553  
         }
 554  3
     }
 555  
 
 556  
     /**
 557  
      * @return null
 558  
      */
 559  
     public String[] createCommandLine( CompilerConfiguration config )
 560  
         throws CompilerException
 561  
     {
 562  0
         return null;
 563  
     }
 564  
 
 565  
 }