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