Does the Gradle javaCompile task always recompile all java classes (including unchanged?) - java

I can get an ant compile to only rebuild java classes that have changed, but I can't get Gradle to do so.
I have a project with the structure
root
/src/main/java
/pkg1/File1.java
/pkg2/File2.java
/build.gradle
/build.xml (for comparing against ant)
File1 and File2 are not dependent on each other. File1 and File2 contain correct package information
my build.gradle file only has 1 line
apply plugin: 'java'
Ant: When I do a ant compile it creates two .class files File1.class and File2.class. When I change File2.java and recompile only File2 gets rebuilt. This is the behavior I expect?
Gradle: When I do a gradle compileJava it creates two .class files File1.class and File2.class. When I change only File2.java and recompile both File1 and File2 are rebuilt. Why is File1 recompiled here?
Could this be due to a configuration issue? Or is it just not possible with Gradle at the moment? Perhaps it's a bad idea to this in the first place, if so, why?
For completeness the ant file looks something like this :
<property name="src" location="src/main/java/"/>
<property name="build" location="build"/>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init" description="compile the source " >
<javac srcdir="${src}" destdir="${build}" includeDestClasses="true"/>
</target>

Gradle doesn't support incremental Java compilation at this time. In other words, if any input of the JavaCompile task changes, all sources will be recompiled. I do expect incremental compilation to be supported in a future release. Until then, compile time can be improved by spreading sources over multiple source sets (which effectively means multiple compile tasks) and projects. The former helps to make up-to-date checks more effective, the latter allows for parallel compilation when running with --parallel.
UPDATE: Gradle now supports incremental building since 2015.

I know this is an old post. Still answering for letting people know about this great and wonderful feature.
The incremental task for gradle is in incubation stage.
Please go through:
https://docs.gradle.org/current/userguide/custom_tasks.html#incremental_tasks
http://gradle.org/feature-spotlight-incremental-builds/
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.incremental.IncrementalTaskInputs.html

Related

How to use ThreeTen in Ant project?

I have some legacy Java 6 project and I want to bring some updates on them like Java 8 time library. I found that is possible by using ThreeTen backport. But I don't know how to use it with Ant build tool. Any good references or examples please ?
Overview:
Download the ThreeTen Backport JAR file into the lib folder of your Ant project
Make sure that JAR files in your lib folder are on the classpath for both compilation and running (this may already be the case).
In your Java source files add imports from org.threeten.bp with subpackages and use the imported classes in your code.
Download JAR
On http://www.threeten.org/threetenbp/, at the top select Releases -> Download to get to the Maven repository. In the first search result (currently threetenbp 1.3.6 from 10-Jul-2017), in the Download column click jar. Download the file (in this case threetenbp-1.3.6.jar) to or move it to the lib folder of your Ant project. Or where you’ve got your external JARs. If you haven’t got such a place, create a folder called lib for it.
Fix your classpath
If you haven’t previously got any external dependencies in the form of external JAR files that your program uses, you may need to prepare your build.xml file for these. In my build.xml I added
<property name="lib.dir" value="lib"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
This defines names for the lib folder and the classpath for use later. Note that I specify that all .jar files in the lib folder with subfolders are on the classpath, so in the future you can just drop JARs in to add them to your project. Then I added the classpath both to my compile target and to my run target:
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
</target>
And
<target name="run" depends="jar">
<java fork="true" classname="${main-class}">
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
We need to fix both targets because the external JAR(s) is/are needed both for compilation and for running.
Use java.time classes in your Java program
Here’s my program. Note that the import statements refer to org.threeten.bp.
package ovv.ant.threetenbp;
import java.util.Date;
import org.threeten.bp.Instant;
import org.threeten.bp.DateTimeUtils;
public class AntAndThreeTenBackportDemo {
public static void main(String... commandLineArguments) {
Instant once = Instant.parse("1939-11-19T16:30:00Z");
Date oldfashionedDateObject = DateTimeUtils.toDate(once);
System.out.println("As Date: " + oldfashionedDateObject);
}
}
When I run from Ant (on my computer in Europe/Copenhagen time zone) I get:
run:
[java] As Date: Sun Nov 19 17:30:00 CET 1939
I used Ant 1.9.7, but I think it’s the same in other versions.
Source and further reading
I used the Ant tutorial here, in particular the Using External Libraries section.

Compiling an eclipse GWT project from the command line, without eclipse: compile error

We got a GWT project in Eclipse, that otherwise works.
Now I want to have a script that runs on the server, which pulls the latest version from source control and compiles it on the server and deploys it.
This will save us a lot of manual work and allow us to deploy new version when on a connection with limited bandwidth (since we won't have to upload the application to the server).
After pulling the latest version of the source code, the script tries to compile the code using the following command:
java -cp "/path/eclipse/plugins/com.google.gwt.eclipse.sdkbundle_2.5.0.v201211121240-rel-r42/gwt-2.5.0/*:/path/company/projects/pull-compile-deploy/X/X/src:/path/company/projects/pull-compile-deploy/X/X/war/WEB-INF/lib/*" com.google.gwt.dev.Compiler nl.company.projects.X
Compiling module nl.company.projects.X
Finding entry point classes
[ERROR] Unable to find type 'nl.company.projects.X.client.XMain'
[ERROR] Hint: Previous compiler errors may have made this type unavailable
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
All source code is in /path/company/projects/pull-compile-deploy/X/X/src and all used .jars (except for the GWT stuff) are in /path/company/projects/pull-compile-deploy/X/X/war/WEB-INF/lib/. Obviously something goes wrong.
Questions: The file /path/company/projects/pull-compile-deploy/X/X/src/nl/company/projects/X/client/XMain.java does exist and should imho be in the classpath?!
Anyone Any idea what might go wrong here?
Is it maybe possible to see in some log exactly the commands that eclipse executes for compilation? I looked at the build.xml that eclipse can export, but it seems that does not contain a target to compile for production.
something else: apperantly GWT expects the X.gwt.xml to be at /path/company/projects/pull-compile-deploy/X/X/src/nl/company/project/X.gwt.xml, whereas eclipse put it in /path/company/projects/pull-compile-deploy/X/X/src/nl/company/project/X/X.gwt.xml (i.e. nested one directory deeper), I fixed this by creating a symbolic link.
Further Edit:
Since one answer focused on how I invoked the compilation tools, I have rewritten that in Ant, see below.
The problem remains of course.
<!-- Compile the source using javac. -->
<target name="compile" depends="init">
<javac srcdir="src/" destdir="bin/">
<classpath refid="project.classpath"/>
</javac>
</target>
<!-- Use the GWT-compiler. -->
<target name="gwt-compile" depends="compile">
<java failonerror="true" fork="true" classname="com.google.gwt.dev.Compiler">
<classpath>
<path refid="project.classpath"/>
<pathelement location="src/"/>
<pathelement location="bin/"/>
</classpath>
<jvmarg value="-Xmx512M"/>
<arg value="${module.name}"/>
</java>
</target>
Anything wrong with the above Ant-script?
module.name = nl.company.projects.X and the path with refid="project.classpath" contains all used libraries aswell as the GWT libraries (gwt-user.jar, gwt-dev.jar and validation-api-1.0.0.GA(-source).jar).
The XMain class inherits nothing (other than from Object) and only implements EntryPoint (which is included in the gwt-user.jar). So I do not think the problem is related to the second hint that the compiler gives.
Any ideas?
GWT requires you to javac your classes, it needs both the *.java and the *.class files.
This has not always been the case, and should change back in the future (see https://code.google.com/p/google-web-toolkit/issues/detail?id=7602 for instance), but for now that's the state of affair: you need to javac before you can com.google.gwt.dev.Compiler.
javac -cp "/path/eclipse/plugins/com.google.gwt.eclipse.sdkbundle_2.5.0.v201211121240-rel-r42/gwt-2.5.0/*:/path/company/projects/pull-compile-deploy/X/X/war/WEB-INF/lib/*" -sourcepath /path/company/projects/pull-compile-deploy/X/X/src /path/company/projects/pull-compile-deploy/X/X/src/nl/company/projects/X.java -d /path/company/projects/pull-compile-deploy/X/X/bin
java -cp "/path/eclipse/plugins/com.google.gwt.eclipse.sdkbundle_2.5.0.v201211121240-rel-r42/gwt-2.5.0/*:/path/company/projects/pull-compile-deploy/X/X/src:/path/company/projects/pull-compile-deploy/X/X/bin:/path/company/projects/pull-compile-deploy/X/X/war/WEB-INF/lib/*" com.google.gwt.dev.Compiler nl.company.projects.X
(please double-check the above commands before use)
EDIT: (in response to your "question" re. the X.gwt.xml): GWT expects the X.gwt.xml at nl/company/projects/X.gwt.xml because that's what you told it to use: module.name = nl.company.projects.x. If the file is at nl/company/projects/X/X.gt.xml then use nl.company.projects.X.X as the module name. Using a symbolic link here is likely to be the problem: the source path for the module (search for <source at https://developers.google.com/web-toolkit/doc/latest/DevGuideOrganizingProjects#DevGuideModuleXml) will then be nl/company/projects/client and thus won't include nl/company/projects/X/client where your XMain class lives; it's this unavailable to the GWT compiler.
That said, I totally agree with SSR: use a decent build tool: Ant, Maven, Gradle, Make, whatever, it'll make your life so much easier. A build tool that manages dependencies (Ant+Ivy, Maven, Gradle) is even better IMO.
Why would you put yourself through such non-standard build exercise like this.
If it is non-academic project then USE maven. If you find maven difficult then use ant.
Examples for both type are provided by GWT team - http://code.google.com/p/google-web-toolkit/source/browse/#svn%2Ftrunk%2Fsamples.
Note - maven has plugins to do most of the stuff you are trying in standardized way.

FindBugs refuses to find bcel jar on classpath

For the life of me, I am trying to get FindBugs (2.0.1) to run as part of my command-line Ant build. I downloaded the FindBugs JAR and extracted it to /home/myuser/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1:
As you can see in the screenshot, under /home/myuser/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1/lib there is a JAR called bcel-1.0.jar, and if you open it, you can see that I have drilled down to a class called org.apache.bcel.classfile.ClassFormatException. Hold that thought.
I then copied /home/myuser/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1/lib/findbugs-ant.jar to ${env.ANT_HOME}/lib to make it accessible to the version of Ant that is ran from the command-line (instead of the Ant instance that comes built-into Eclipse).
My project directory structure is as follows:
/home/myuser/sandbox/workbench/eclipse/workspace/myapp/
src/
main/
java/
test/
java/
build/
build.xml
build.properties
gen/
bin/
main/ --> where all main Java class files compiled to
test/ --> where all test Java class files compiled to
audits/
qual/
staging/
Inside build.xml:
<project name="myapp-build" basedir=".." default="package"
xmlns:fb="antlib:edu.umd.cs.findbugs">
<path id="findbugs.source.path">
<fileset dir="src/main/java">
<include name="**.*java"/>
</fileset>
<fileset dir="src/main/test">
<include name="**.*java"/>
</fileset>
</path>
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"
uri="antlib:edu.umd.cs.findbugs"/>
<!-- Other Ant target omitted for brevity. -->
<target name="run-findbugs">
<!-- Create a temp JAR that FindBugs can use for analysis. -->
<property name="fb.tmp.jar" value="gen/staging/${ant.project.name}-findbugs-temp.jar"/>
<echo message="Creating ${fb.tmp.jar} for FindBugs."/>
<jar destfile="gen/staging/${ant.project.name}-findbugs-temp.jar">
<fileset dir="gen/bin/main" includes="**/*.class"/>
<fileset dir="gen/bin/test" includes="**/*.class"/>
</jar>
<echo message="Conducting code quality tests with FindBugs."/>
<fb:findbugs home="/home/myuser/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1"
output="html" outputFile="gen/audits/qual/findbugs.html" stylesheet="fancy-hist.xsl" failOnError="true">
<sourcePath refid="findbugs.source.path"/>
<class location="${fb.tmp.jar}"/>
</fb:findbugs>
</target>
<target name="echoMsg" depends="run-findbugs">
<echo message="The build is still alive!!!"/>
</target>
</project>
But when I run ant -buildfile build.xml echoMsg from the command-line, I get an error in FindBugs:
run-findbugs:
[echo] Creating gen/staging/myapp-build-findbugs-temp.jar for FindBugs.
[jar] Building jar: /home/myuser/sandbox/workbench/eclipse/workspace/myapp/gen/staging/myapp-build-findbugs-temp.jar
[echo] Conducting code quality tests with FindBugs.
[fb:findbugs] Executing findbugs from ant task
[fb:findbugs] Running FindBugs...
[fb:findbugs] Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/bcel/classfile/ClassFormatException
[fb:findbugs] Caused by: java.lang.ClassNotFoundException: org.apache.bcel.classfile.ClassFormatException
[fb:findbugs] at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
[fb:findbugs] at java.security.AccessController.doPrivileged(Native Method)
[fb:findbugs] at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
[fb:findbugs] at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
[fb:findbugs] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
[fb:findbugs] at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
[fb:findbugs] Could not find the main class: edu.umd.cs.findbugs.FindBugs2. Program will exit.
[fb:findbugs] Java Result: 1
[fb:findbugs] Output saved to gen/audits/qual/findbugs.html
echoMsg:
[echo] The build is still alive!!!
Here's what has me amazed:
Even with failOnError="true", FindBugs is not halting the build even when this runtime exception is encountered
The last piece of output "Output saved to gen/audits/qual/findbugs.html" is a lie! There is nothing in gen/audits/qual!
The bcel-1.0.jar is absolutely under FindBugs home, just like every other JAR in the lib/ directory.
Please note: the findbugs-ant.jar is definitely copied to ANT_HOME/lib; otherwise I would be getting a failed build complaining that it couldn't find the Ant tasks. As a sanity check, I went ahead and did this (I deleted the findbugs-ant.jar from ANT_HOME/lib and got a failed build). This build doesn't fail (it succeeds!). It just doesn't run findbugs.
Can anyone spot what is going on here? Thanks in advance!
You can debug where BCEL is being loaded from using the -verbose:class argument to the jvm.
To pass this argument to the jvm running findbugs, use the jvmargs flag on the find bugs plugin
jvmargs
Optional attribute. It specifies any arguments that should be
passed to the Java virtual machine used to run FindBugs. You may need
to use this attribute to specify flags to increase the amount of
memory the JVM may use if you are analyzing a very large program.
How did you populate the find bugs lib jar? When I download findbugs.zip, I get a lib directory which looks very different than what you show. In particular, mine contains a bcel with a version of 5.3, not 1.0 as you show.
Funny thing because I am using the same version of Findbugs and the jar file is named bcel.jar not bcel-1.0.jar. I am also running Findbugs from an Ant script. As crazy as it might sound, try to download the Findbugs once again, unpack it in the place of your current one and run your script once again.
My guess is that you actually have BCEL in the classpath twice. And the file is being loaded from the jar outside the FindBugs library. Then, when FindBugs tries to load the jar, it finds the BCEL in the FindBugs library and cannot load it, because it's already loaded.
The solution would be to find where else BCEL exists in the classpath and remove it.
You might have to define a AuxClasspath to include the classpath that your <javac> task used when compiling your class files.
You don't show how the compile took place, so I am assuming your created a compile.classapath classpath reference:
<javac destdir="gen/bin/main"
srcdir="src/main/java"
classpathref="compile.classpath"/>
<fb:findbugs home="/home/myuser/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1"
output="html" outputFile="gen/audits/qual/findbugs.html" stylesheet="fancy-hist.xsl" failOnError="true">
<auxClasspath refid="compile.classpath"/>
<sourcePath refid="findbugs.source.path"/>
<class location="${fb.tmp.jar}"/>
</fb:findbugs>
I don't see from your Ant script that bcel is landing on any classpath that the findbugs task would be able to load it from. You might want to try making your taskdef explicitly include everything findbugs needs.
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"
uri="antlib:edu.umd.cs.findbugs">
<classpath>
<fileset dir="/home/java/repo/umd/findbugs/2.0.1/findbugs-2.0.1">
<include name="*.jar"/>
</fileset>
</classpath>
</taskdef>
most classpath problems you can debug with tattle. it will report you all jars in your project. all duplicated classes etc. saved me a lot of time.
there is also ant task ready: http://docs.jboss.org/tattletale/userguide/1.2/en-US/html/ant.html

Ant Javac and Commandline Javac give different results

I have a class that imports some servlet libraries. When I compile it from command-line it is fine.
When I use the ant compile task to compile it, it gives the errors that it can't find the servlet libraries in its path.
Is that a known/common occurrence?
Here is my Ant target:
<target name="compile" depends="prepare" description="compile the source" >
<echo>=== COMPILE === SRCDIR: ${src}/com/udfr/src/java </echo> <!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}/com/udfr/src/java" destdir="${dist}/WEB-INF/classes"/>
</target>
It's a common occurrence if you don't specify the servlet libraries properly in the classpath for the javac task... I suspect that's the problem. If you post the task which fails and the command line which works, we'll be able to help more.
For some reason, the JAR file containing the Servlet API is part of your classpath when you compile your program in command line. However, it's not in the classpath of the javac Ant task.
You should explicitely add the JAR file to the classpath in your javac Ant task. There are several ways to do that; please read http://ant.apache.org/manual/Tasks/javac.html

Run some or all sections of an ant file

Is there a way to specify an ANT file to run only one/some/all of its sections?
Split your build into appropriate targets so that you can call individual targets separately, and then you can specify the target you want to run from the command line.
Personally I like having "real" targets without any dependencies (which I can run independently) and then "fake" targets which are just dependent on the real ones, for convenience (e.g. "clean-build"). The alternative of having test depend on compile etc always ends up getting in the way for me :(
You can group targets together using dependencies:
<target name="A">
<target name="B">
<target name="C" depends="A,B">
runs
A, B, then C.
You can also chain these to arbitrary depth. For example you could create an empty target "D" that depends on A, B which will only run A and B.
<project....
<target name="all">
...
</target>
<target name="some">
...
</target>
</project>
run
ant all
or
ant some
Define appropriate targets in your build file and then run
ant 'target name'
to run that particular one. You will have to configure target dependencies such that the ones you want to run separately can do so correctly.
It's a good practise to define these top-level targets with a description.
<target name="clean" description="Cleans up built artifacts">
Then you can run
ant -projecthelp
and this will display the targets with descriptions, thus telling you what targets are available. This will make life a lot easier further down the road, when you've forgotten what targets you've defined.

Categories

Resources