Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin doesn't detect recompiled files #15

Open
odrotbohm opened this issue Apr 6, 2016 · 16 comments
Open

Plugin doesn't detect recompiled files #15

odrotbohm opened this issue Apr 6, 2016 · 16 comments

Comments

@odrotbohm
Copy link

The Maven compiler plugin currently always recompiles sources, even if there have been any changes at all (see these tickets for details). That recompilation however is not recognized by the AspectJ Maven plugin and it just skips AspectJ compilation on subsequent runs.

To reproduce:

$ git clone https://github.com/spring-projects/spring-data-jpa
$ cd spring-data-jpa
$ mvn clean package -DskipTests
…
[INFO] --- maven-compiler-plugin:3.3:compile (default-compile) @ spring-data-jpa ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 101 source files to /Users/olivergierke/Documents/workspace/spring-data-jpa/target/classes
… 
[INFO] --- aspectj-maven-plugin:1.8:compile (default) @ spring-data-jpa ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[WARNING] You aren't using a compiler supported by lombok, so lombok will not work and has been disabled.
Your processor is: org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.BatchProcessingEnvImpl
Lombok supports: sun/apple javac 1.6, ECJ
    <unknown source file>:<no line information>
[INFO]
$ mvn package -DskipTests
…
[INFO] --- maven-compiler-plugin:3.3:compile (default-compile) @ spring-data-jpa ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 101 source files to /Users/olivergierke/Documents/workspace/spring-data-jpa/target/classes
…
[INFO] --- aspectj-maven-plugin:1.8:compile (default) @ spring-data-jpa ---
[INFO] No modifications found skipping aspectJ compile
…

See the last line. The plugin skips the compilation step although the compiler plugin has recompiled the code and we end up with classes that haven't got any aspects applied.

@odrotbohm
Copy link
Author

I currently work around this by setting the forceAjcCompile property to true.

odrotbohm added a commit to spring-projects/spring-data-jpa that referenced this issue Apr 6, 2016
We now enforce the AspectJ plugin to run no matter what to work around bugs in the plugin in combination with bugs in the compiler plugin.

mojohaus/aspectj-maven-plugin#15
https://issues.apache.org/jira/browse/MCOMPILER-205
https://issues.apache.org/jira/browse/MCOMPILER-209
odrotbohm added a commit to spring-projects/spring-data-jpa that referenced this issue Apr 6, 2016
We now enforce the AspectJ plugin to run no matter what to work around bugs in the plugin in combination with bugs in the compiler plugin.

mojohaus/aspectj-maven-plugin#15
https://issues.apache.org/jira/browse/MCOMPILER-205
https://issues.apache.org/jira/browse/MCOMPILER-209
@SunShineShine
Copy link

I tried to set forceAjcCompile property to true,but it still doesn't work,do you have any other way to solve the problem

@bmarwell
Copy link
Contributor

@odrotbohm sorry for the late answer. Does it still apply?
I can write an integration test if needed.
The problem must be in these lines:

private boolean hasSourcesChanged(File outDir) {
long lastBuild = new File(outDir, argumentFileName).lastModified();
for (String source : resolvedIncludes) {
File sourceFile = new File(source);
long sourceModified = sourceFile.lastModified();
if (sourceModified >= lastBuild) {
return true;
}
}
return false;
}
private boolean hasNonWeavedClassesChanged(File outDir)
throws MojoExecutionException {
if (weaveDirectories != null && weaveDirectories.length > 0) {
Set<String> weaveSources = AjcHelper.getWeaveSourceFiles(weaveDirectories);
long lastBuild = new File(outDir, argumentFileName).lastModified();
for (String source : weaveSources) {
File sourceFile = new File(source);
long sourceModified = sourceFile.lastModified();
if (sourceModified >= lastBuild) {
return true;
}
}
}
return false;
}

I tried to set forceAjcCompile property to true,but it still doesn't work,do you have any other way to solve the problem

That is odd:

        if (!forceAjcCompile && !isBuildNeeded()) {
            getLog().info("No modifications found skipping aspectJ compile");
            return;
        }

@bmarwell bmarwell added the stale label Jun 14, 2021
trayanus1026 pushed a commit to trayanus1026/spring-data-jpa-java that referenced this issue Aug 5, 2023
We now enforce the AspectJ plugin to run no matter what to work around bugs in the plugin in combination with bugs in the compiler plugin.

mojohaus/aspectj-maven-plugin#15
https://issues.apache.org/jira/browse/MCOMPILER-205
https://issues.apache.org/jira/browse/MCOMPILER-209
@filnet
Copy link

filnet commented Sep 6, 2023

Seeing the same issue with maven-aspectj-plugin 1.14.0 and maven-compiler-plugin 3.11.0.

[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ project ---
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 419 source files with javac [debug target 1.8] to target\classes
[INFO]
[INFO] --- aspectj-maven-plugin:1.14.0:compile (default) @ project ---
[INFO] No modifications found skipping aspectJ compile

Maven re-compiles the classes that need to be weaved but weaving does not happen.

The forceAjcCompile workaround works.

@kriegaex
Copy link
Collaborator

kriegaex commented Sep 12, 2023

I cannot confirm that this happens. Neither does Maven Compiler always recompile all source files, nor do aspects not get applied after a recompile, at least not in a simple single-module test project:

$ mvn clean
(...)

$ mvn -Dmaven.compiler.showCompilationChanges compile

(...)
[INFO] --- compiler:3.11.0:compile (default-compile) @ my-application ---
[INFO] Stale source detected: ...\src\main\java\com\carrot\personal\app\SpecialApp.java
[INFO] Stale source detected: ...\src\main\java\com\carrot\personal\app\DataTrackHelper.java
[INFO] Stale source detected: ...\src\main\java\com\carrot\personal\aspects\DataTrackAspect.java
[INFO] Stale source detected: ...\src\main\java\com\carrot\personal\app\Application.java
[INFO] Stale source detected: ...\src\main\java\com\carrot\personal\aspects\DataTrackEnabled.java
[INFO] Changes detected - recompiling the module! :source
[INFO] 	+ ...\src\main\java\com\carrot\personal\app\SpecialApp.java
[INFO] 	+ ...\src\main\java\com\carrot\personal\aspects\DataTrackAspect.java
[INFO] 	+ ...\src\main\java\com\carrot\personal\app\DataTrackHelper.java
[INFO] 	+ ...\src\main\java\com\carrot\personal\aspects\DataTrackEnabled.java
[INFO] 	+ ...\src\main\java\com\carrot\personal\app\Application.java
[INFO] Compiling 5 source files with javac [debug target 11] to target\classes
[INFO] 
[INFO] --- aspectj:1.13.1:compile (default) @ my-application ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(int Person.getId())' in Type 'Person' (NegatedTypeAspect.aj:41) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:6)
[INFO] Join point 'method-execution(int Person.getId())' in Type 'Person' (NegatedTypeAspect.aj:41) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:2)
[INFO] Join point 'method-execution(void Person.setId(int))' in Type 'Person' (NegatedTypeAspect.aj:45) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:10)
[INFO] Join point 'method-execution(java.lang.String Person.getLastName())' in Type 'Person' (NegatedTypeAspect.aj:49) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:2)
[INFO] Join point 'method-execution(void Person.setLastName(java.lang.String))' in Type 'Person' (NegatedTypeAspect.aj:53) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:10)
[INFO] Join point 'method-execution(java.lang.String Person.getFirstName())' in Type 'Person' (NegatedTypeAspect.aj:57) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:2)
[INFO] Join point 'method-execution(void Person.setFirstName(java.lang.String))' in Type 'Person' (NegatedTypeAspect.aj:61) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:10)
[INFO] Join point 'method-execution(void Person.setFullName(java.lang.String))' in Type 'Person' (NegatedTypeAspect.aj:73) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:10)
[INFO] Join point 'method-execution(void Person.getVoid())' in Type 'Person' (NegatedTypeAspect.aj:90) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:6)
[INFO] Join point 'method-execution(java.lang.String com.carrot.personal.app.Application$User.getFirstName())' in Type 'com.carrot.personal.app.Application$User' (Application.java:41) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:2)
[INFO] Join point 'method-execution(java.lang.String com.carrot.personal.app.Application$User.getLastName())' in Type 'com.carrot.personal.app.Application$User' (Application.java:45) advised by before advice from 'NegatedTypeAspect' (NegatedTypeAspect.aj:2)
[INFO] Join point 'method-execution(java.util.Map com.carrot.personal.app.Application.fetchUser())' in Type 'com.carrot.personal.app.Application' (Application.java:33) advised by around advice from 'com.carrot.personal.aspects.DataTrackAspect' (DataTrackAspect.java:11)
(...)

$ mvn -Dmaven.compiler.showCompilationChanges compile

(...)
[INFO] --- compiler:3.11.0:compile (default-compile) @ my-application ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- aspectj:1.13.1:compile (default) @ my-application ---
[INFO] No modifications found skipping aspectJ compile
(...)

A minimal reproducer project would be helpful.

BTW, is there anything keeping you from simply deactivating Maven Compiler completely in the modules using AspectJ Maven? AJC is based on ECJ and therefore a full replacement for Javac. Then you would not have this problem in the first place. I am talking about adding something like this:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.11.0</version>
  <executions>
    <execution>
      <id>default-compile</id>
      <phase>none</phase>
    </execution>
    <execution>
      <id>default-testCompile</id>
      <phase>none</phase>
    </execution>
  </executions>
  <configuration>
    <source>11</source>
    <target>11</target>
  </configuration>
</plugin>

Of course, if there really was a problem is AJ Maven, this would just be a workaround and we should still investigate the original problem, but for that a reproducer is necessary.

@filnet
Copy link

filnet commented Sep 12, 2023

I think you need two projects:

  • a plain jar project
  • a second project that depends on the 1st project and uses AJ.

If you change the 1st project, the 2nd project will be recompiled too because one of its dependencies changed.

You'll see such a message for the second project:
[INFO] Changes detected - recompiling the module! :dependency
When that happens the 2nd project gets compiled but no AJ.

[EDIT] I am seeing the issue with Maven 3.8.3.

@kriegaex
Copy link
Collaborator

kriegaex commented Sep 13, 2023

Sorry @filnet, but when I use a separate project and mvn install it, my dependent Maven project does not recompile anything. Even if in the dependency I change a method signature in a way that would make the dependent project fail on recompile, no change in the dependency is picked up and Maven Compiler 3.11.0 does absolutely nothing:

[INFO] --- compiler:3.11.0:compile (default-compile) @ my-application ---
[INFO] Nothing to compile - all classes are up to date

Only if instead of mvn compile I use mvn clean compile, will it detect the dependency change and throw an error during compilation.

So, if this does not even work in Maven Compiler, how is AspectJ Maven expected to react on the dependency change?

If it is so easy to reproduce, where is the MCVE? I do not want to keep guessing and using trial & error to reproduce it, before I can even think about analysing and fixing it.

@filnet
Copy link

filnet commented Sep 14, 2023

@kriegaex, I made a small project that reproduces the issue : https://github.com/filnet/maven-aspectj-plugin-issue

Steps to reproduce:

  • Compile the project with mvn compile from the root of the project.
  • Edit the file ./project1/src/main/java/BaseModel.java
  • Compile the project again (again from the root of the project).

You should see that project2 is recompiled because maven detected that its dependency project1 has changed.
The ./project2/src/main/java/Model.java file gets recompiled but not weaved.

This is the output I get for project2:

[INFO] --------------------------< project:project2 >--------------------------
[INFO] Building project2 1.0.0                                            [4/4]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ project2 ---
[INFO] skip non existing resourceDirectory C:\bug\project2\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ project2 ---
[INFO] New dependency detected: C:\bug\project1\target\classes
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 1 source file with javac [debug target 1.8] to target\classes
[INFO]
[INFO] --- aspectj-maven-plugin:1.14.0:compile (default) @ project2 ---
[INFO] No modifications found skipping aspectJ compile

@kriegaex
Copy link
Collaborator

kriegaex commented Sep 19, 2023

I think you need two projects:

  • a plain jar project
  • a second project that depends on the 1st project and uses AJ.

I made a small project that reproduces the issue : https://github.com/filnet/maven-aspectj-plugin-issue

Yeah, now we are getting there. So the problem is not two projects but rather one multi-module project where module B depends on module A and there are undetected changes in A when building B.

Unfortunately, this is not so much a bug, but rather a total lack of functionality in AJ Maven. The plugin simply does not check at all if there have been changes in any dependency class file directories or JARs in the same project.

kriegaex added a commit to dev-aspectj/aspectj-maven-plugin that referenced this issue Sep 19, 2023
@kriegaex
Copy link
Collaborator

kriegaex commented Sep 19, 2023

I added a quick fix to dev.aspectj:aspectj-maven-plugin:1.13.2-SNAPSHOT, forked your project, modified it a bit to first reproduce the problem with plugin version 1.13.1 and then re-test the plugin fix in the snapshot version.

See also PR filnet/maven-aspectj-plugin-issue#1.

The reason why I choose to maintain the AspectJ.dev plugin fork rather than contribute to this one are partly historical in nature and partly because it enables me as the core AspectJ maintainer to add changes without having to debate with Mojohaus maintainers and release versions keeping up with latest AspectJ development.

To the Mojohaus team: Feel free to cherry-pick the fix from my fork dev-aspectj/aspectj-maven-plugin@7b8706a or devise a better solution. 🙂

I am not particularly happy with the change, but presently I do not have more time to make it more beautiful. The things I do not like about the code also apply to other parts of the plugin, which I have not refactored in order to keep it more compatible with the Mojohaus version regarding cherry-picks in either direction.

kriegaex added a commit to dev-aspectj/aspectj-maven-plugin that referenced this issue Dec 19, 2023
More exactly, in AbstractAjcCompiler::hasClassPathClassesChanged.

Relates to mojohaus/aspectj-maven-plugin#15.
@kriegaex
Copy link
Collaborator

kriegaex commented Dec 19, 2023

@filnet, would you mind to test with my fix from 3 months ago and report back if it solves the problem for you? I just stumbled across this piece of code again in another context and remembered that back then I got no feedback.

@odrotbohm, you as the person who raised the issue are welcome to test, too.

@kriegaex
Copy link
Collaborator

kriegaex commented Dec 19, 2023

@odrotbohm, I analysed your problem (which is different from @filnet's example) in my comment on MCOMPILER-194. It really is a Maven Compiler (MC) problem, not an AspectJ Maven (AJM) one, IMO. Even if I deactivate AJM in your project, MC will still falsely recompile everything.

The Maven compiler plugin currently always recompiles sources, even if there have been any changes at all

In your project, that seems to be the case, but like I said before, MC does not always do that. Your project uses all kinds of special things that might influence why MC thinks something has changed, e.g. I noticed

  • annotation processing in the MC step,
  • Gradle Enterprise Maven Extension, which tries to be smart with caching stuff.

That recompilation however is not recognized by the AspectJ Maven plugin and it just skips AspectJ compilation on subsequent runs.

AJM looks at changed source files and (since my fix in the snapshot version a few months ago) dependencies. It is not AJM's job to try to find out what MC did by indirectly checking class file timestamps or agree with MC's opinion about whether a recompile is necessary or not. Both MC and AJM look as source files and dependencies independently of each other. What other smart(?) things MC tries to do on top of that, I have no idea ATM.

Like I said in Jira, simply make sure that MC and AJM do not fight each other, trying to compile the same source files. If you really want to run both plugins and not e.g. use AJM as a full replacement for MC and deactivate MC's executions, you need to make sure that the sets of classes the two plugins compile are disjoint (i.e. their intersecting set is empty).

@filnet
Copy link

filnet commented Dec 19, 2023

@kriegaex

I merged your test project PR and got this error when compiling:

ERROR] Plugin dev.aspectj:aspectj-maven-plugin:1.13.2-SNAPSHOT or one of its dependencies could not be resolved: Could not find artifact dev.aspectj:aspectj-maven-plugin:jar:1.13.2-SNAPSHOT in ossrh-snapshots (https://oss.sonatype.org/content/repositories/snapshots) -> [Help 1]

Changed the repository URL to https://s01.oss.sonatype.org/content/repositories/snapshots and now get this error:

[ERROR] Failed to execute goal dev.aspectj:aspectj-maven-plugin:1.13.2-SNAPSHOT:compile (default) on project annotation: Execution default of goal dev.aspectj:aspectj-maven-plugin:1.13.2-SNAPSHOT:compile failed: An API incompatibility was encountered while executing dev.aspectj:aspectj-maven-plugin:1.13.2-SNAPSHOT:compile: java.lang.UnsupportedClassVersionError: org/aspectj/ajdt/internal/compiler/ICompilerAdapterFactory has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

I am still on Java 8.

@kriegaex
Copy link
Collaborator

kriegaex commented Dec 19, 2023

@filnet: FAQ: Why does the plugin not run on my JDK version?

Either upgrade your JDK or downgrade your AspectJ version according to the FAQ in my fork's read-me scroll up one paragraph for how to do that im Maven.

@filnet
Copy link

filnet commented Dec 19, 2023

I downgraded AspectJ and the fix seems to work.

After modifying project1, project2 is compiled as expected.

$ ls -lart project2/target/classes/
total 13
drwxr-xr-x 1 philippe.renon 1049089    0 Dec 19 10:55  .
drwxr-xr-x 1 philippe.renon 1049089    0 Dec 19 12:26  ..
-rw-r--r-- 1 philippe.renon 1049089  653 Dec 19 12:36  builddef.lst
-rw-r--r-- 1 philippe.renon 1049089 2342 Dec 19 12:36  Model.class
-rw-r--r-- 1 philippe.renon 1049089  683 Dec 19 12:36 'Model$AjcClosure1.class'

kriegaex added a commit to kriegaex/spring-data-jpa that referenced this issue Dec 21, 2023
by separation of concerns: Let
  - Maven Compiler do annotation processing without compilation and
  - AspectJ Maven compilation of all Java sources and aspects without
    annotation processing.

Actually, we could let AJ Maven do all the work, but it would be
difficult to configure everything correctly in JDK 9+, because AJ Maven
is incomplete regarding automatically putting everything on the right
module paths. so, this separation of concerns saves tedious
configuration work.

Relates to mojohaus/aspectj-maven-plugin#15.
kriegaex added a commit to kriegaex/spring-data-jpa that referenced this issue Dec 21, 2023
This is a workaround for the fact that ANTLR4 Maven Plugin always
generates source files, even if its input files have not changed, which
in turn leads to changed source files and then to unnecessary
compilation of same.

A similar workaround makes sure that in the same situation Maven
Replacer Plugin does not find any files to replace text in, because that
would also alter the timestamps of the target files.

Maven Build Helper Plugin is used to compare ANTLR4 input and output
directories, determining if the latter are up-to-date. If so, the two
plugins mentioned above will be fed a dummy directory name, otherwise a
real one.

Along the way, Maven Replacer was upgraded from 1.4.1 to its last
release 1.5.3, before it was retired on Google Code. The upgrade also
led to renaming the plugin, probably because the word "plugin" is
already in its group ID. But it is, in fact, the same plugin. The
upgrade also fixes a bug, enabling the plugin to understand absolute
directories, i.e. now we can use ''${project.build.directory}' instead
of 'target' as a base directory.

Relates to mojohaus/aspectj-maven-plugin#15.
mp911de pushed a commit to spring-projects/spring-data-jpa that referenced this issue Dec 27, 2023
by separation of concerns: Let
  - Maven Compiler do annotation processing without compilation and
  - AspectJ Maven compilation of all Java sources and aspects without
    annotation processing.

Actually, we could let AJ Maven do all the work, but it would be
difficult to configure everything correctly in JDK 9+, because AJ Maven
is incomplete regarding automatically putting everything on the right
module paths. so, this separation of concerns saves tedious
configuration work.

Relates to mojohaus/aspectj-maven-plugin#15.

See #3282
mp911de pushed a commit to spring-projects/spring-data-jpa that referenced this issue Dec 27, 2023
by separation of concerns: Let
  - Maven Compiler do annotation processing without compilation and
  - AspectJ Maven compilation of all Java sources and aspects without
    annotation processing.

Actually, we could let AJ Maven do all the work, but it would be
difficult to configure everything correctly in JDK 9+, because AJ Maven
is incomplete regarding automatically putting everything on the right
module paths. so, this separation of concerns saves tedious
configuration work.

Relates to mojohaus/aspectj-maven-plugin#15.

See #3282
kriegaex added a commit to dev-aspectj/aspectj-maven-plugin that referenced this issue Feb 11, 2024
While analysing and fixing mojohaus/aspectj-maven-plugin#15, it was
helpful to know the value of each of the 4 conditions determining the
method's return value.
@kriegaex
Copy link
Collaborator

FYI, AspectJ.dev AspectJ Maven Plugin 1.14 containing the fix for this problem has been released and is available on Maven Central.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants