I'm debugging the JDK source like:
public static int codePointAt(CharSequence seq, int index) {
char c1 = seq.charAt(index++);
if (isHighSurrogate(c1)) {
if (index < seq.length()) {
char c2 = seq.charAt(index);
if (isLowSurrogate(c2)) {
return toCodePoint(c1, c2);
}
}
}
return c1;
}
and I want to see c1 variable before I step into if (isHighSurrogate(c1)).
However, when I debug watch c1 variable
it display :
I really have tried added rt.jar source, and it really can step into breakpoint of JDK source, like:
but why c1 variable can't display?
Generally speaking, to be able to watch the variables while stepping through JDK source code, you need the class files to be compiled with debug information i.e. compile using javac -g.
So your best bet is to either find an already compiled version with debug information (I couldn't find anything for JDK 7) or you can try compiling the source for yourself.
According to this post (please note that I haven't tried it) you don't need to compile all sources, only the ones you need. Putting your newly compiled classes in the $jdk/jre/lib/ext/endorsed directory, the new classes would be used instead the ones in the original rt.jar.
I believe that should get you started.
Update: Actually I have just tried this process and it is not hard at all. Tested on Windows, JDK 1.7.0_11. All the commands are invoked from command line:
Create your working folder. I chose d:\ root folder
Inside your working folder create the source folder i.e. jdk7_src and output folder jdk_debug
From your JDK_HOME folder get the src.zip file and unzip it inside jdk7_src
Select what you will compile and delete the rest. For all of them you might need additional steps. I have chosen the folders:
java
javax
org
From your JDK_HOME\jre\lib get the file rt.jar and put in the work folder (this is only for convenience to not specify too large file names in the command line).
Execute the command: dir /B /S /X jdk7_src\*.java > filelist.txt to create a file named filelist.txt with the list of all java files that will be compiled. This will be given as input to javac
Execute javac using the command:
javac -J-Xms16m -J-Xmx1024m -sourcepath d:\jdk7_src -cp d:\rt.jar -d d:\jdk_debug -g #filelist.txt >> log.txt 2>&1 This will compile all the files in the jdk_debug folder and will generate a log.txt file in your working folder. Check the log contents. You should get a bunch of warnings but no error.
Go inside the jdk_debug folder and run the command: jar cf0 rt_debug.jar *. This will generate your new runtime library with degug information.
Copy that new jar to the folder JDK_HOME\jre\lib\endorsed. If the endorsed folder does not exist, create it.
Debug your program in Eclipse. Note how the variables are named normally (no more arg0, arg1 etc). Happy debugging :)
c-s's jre\lib\endorsed solution is great.
Easier to build is with Eclipse: create a Java project, put javax*, java* into src and let Eclipse compile. Then export the jar.
This article http://www.thejavageek.com/2016/04/03/debug-jdk-source-code/ describe the same but in simple and nice way. You do stuff(compile,make jar) by using eclipse only.
Just so you know, the endorsed override mechanism is deprecated and will be removed in a future release (http://docs.oracle.com/javase/8/docs/technotes/guides/standards/).
Use this pom.xml to get JDK 1.8.0_111 sources with debug information:
<project>
<modelVersion>4.0.0</modelVersion>
<name>JDK sources with debug information</name>
<groupId>ex.jdk.debug</groupId>
<artifactId>jdk-debug-sources</artifactId>
<version>1.8.0_111</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>jdk-rt</artifactId>
<version>1.8.0_111</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<debug>true</debug>
<debuglevel>lines,vars,source</debuglevel>
<source>1.8</source>
<target>1.8</target>
<excludes>
<exclude>com/sun/java/swing/**</exclude>
<exclude>com/sun/source/util/**</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
You'll have to do a manual install of the original rt.jar to be able to run mvn clean install
mvn install:install-file -Dfile=rt.jar -DgroupId=com.oracle -DartifactId=jdk-rt -Dversion=1.8.0_111 -Dpackaging=jar
The rt.jar I copied to the endorsed directory is the original rt.jar but with the original classes replaced by my newly generated classes.
In case anybody needs this with tomcat. You need to set up the VM argument Djava.endorsed.dirs and put your compiled jdk jar in it. You can do this c-s's solution or exported with eclipse(all the Java Compiler ClassFile Generation used by de debugger must be active)
Go to Run Configurations > Arguments > VM arguments
Djava.endorsed.dirs="/your/folder/apache-tomcat-xxx/endorsed"
Related
I'm using a parser generator that creates somewhat ugly code. As a result my Eclipse project has several dozen warnings emanating from generated source files. I know I can use the #SuppressWarning annotation to suppress particular warnings in particular elements, but any annotations I add by hand will be lost when the parser generator runs again. Is there a way to configure Eclipse to suppress warnings for a particular file or directory?
Starting with version 3.8 M6, Eclipse (to be exact: the JDT) has built-in functionality for this. It is configurable through a project's build path: Project properties > Java Build Path > Compiler > Source
Announced here: Eclipse 3.8 and 4.2 M6 - New and Noteworthy, called Selectively ignore errors/warnings from source folders. That's also where the screenshot is from. This is the new feature developed on the previously linked Bug 220928.
There is a ticket for this, Bug 220928, that has since been completed for Eclipse 3.8. Please see this answer for details.
If you're stuck with Eclipse 3.7 or lower: The user "Marc" commenting on that ticket created (or at least links to) a plugin called 'warningcleaner' in comment 35. I'm using that with a lot of success while waiting for this feature to be integrated into Eclipse.
It's really quite simple:
Install plugin.
Right-click project and select "Add/remove generated code nature".
Open the project settings (right-click and select "properties").
Open the tab 'Warning Cleaner'.
Select the source folders you want to ignore the warnings from.
I solved this by using the maven regexp replace plugin - it does not solve the cause, but heals the pain:
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>maven-replacer-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>target/generated-sources/antlr/**/*.java</include>
</includes>
<regex>true</regex>
<regexFlags>
<regexFlag>MULTILINE</regexFlag>
</regexFlags>
<replacements>
<replacement>
<token>^public class</token>
<value>#SuppressWarnings("all") public class</value>
</replacement>
</replacements>
</configuration>
</plugin>
Note that I did not manage to get the ** notation to work, so you might have to specify path exactly.
See comment below for an improvement on how not to generate duplicate #SupressWarnings
I think the best you can do is enable project specific settings for displaying warnings.
Window -> Preferences -> Java -> Compiler -> Errors/Warnings
On the top of the form is a link for configuring project specific settings.
User #Jorn hinted at Ant code to do this. Here's what I have
<echo>Adding #SuppressWarnings("all") to ANTLR generated parser/lexer *.java</echo>
<echo> in ${project.build.directory}/generated-sources/antlr/</echo>
<replace dir="${project.build.directory}/generated-sources/antlr/"
summary="true"
includes="**/*.java"
token="public class"
value='#SuppressWarnings("all") public class' />
Note that Ant's <replace> does text replacement, not regular expression replacement,
so it cannot use the ^ meta-character in the token to match beginning of line as the maven regexp replace plugin does.
I'm doing this at the same time that I run Antlr from maven-antrun-plugin in my Maven pom, because the ANTLR maven plugin did not play well with the Cobertura maven plugin.
(I realize this is not an answer to the original question, but I can't format Ant code in a comment/reply to another answer, only in an answer)
I don't think Eclipse inherently provides a way to do this at the directory level (but I'm not sure).
You could have the generated files go into a separate Java project, and control warnings for that specific project.
I generally prefer to place automatically-generated code in a separate project anyway.
You can only suppress warnings at the project level. However, you can configure your problems tab to suppress warnings from files or packages. Go into the Configure Contents menu and work with the "On working set:" scope.
This small python script "patches" the M2E-generated .classpath files and adds the required XML tag to all source folders starting with target/generated-sources. You can just run it from you project's root folder. Obviously you need to re-run it when the Eclipse project information is re-generated from M2E. And all at your own risk, obviously ;-)
#!/usr/bin/env python
from xml.dom.minidom import parse
import glob
import os
print('Reading .classpath files...')
for root, dirs, files in os.walk('.'):
for name in files:
if (name == '.classpath'):
classpathFile = os.path.join(root, name)
print('Patching file:' + classpathFile)
classpathDOM = parse(classpathFile)
classPathEntries = classpathDOM.getElementsByTagName('classpathentry')
for classPathEntry in classPathEntries:
if classPathEntry.attributes["path"].value.startswith('target/generated-sources'):
# ensure that the <attributes> tag exists
attributesNode = None;
for attributes in classPathEntry.childNodes:
if (attributes.nodeName == 'attributes'):
attributesNode = attributes
if (attributesNode == None):
attributesNode = classpathDOM.createElement('attributes')
classPathEntry.appendChild(attributesNode)
# search if the 'ignore_optional_problems' entry exists
hasBeenSet = 0
for node in attributesNode.childNodes:
if (node.nodeName == 'attribute' and node.getAttribute('name') == 'ignore_optional_problems'):
# it exists, make sure its value is true
node.setAttribute('value','true')
#print(node.getAttribute('name'))
hasBeenSet = 1
if (not(hasBeenSet)):
# it does not exist, add it
x = classpathDOM.createElement("attribute")
x.setAttribute('name','ignore_optional_problems')
x.setAttribute('value','true')
attributesNode.appendChild(x)
try:
f = open(classpathFile, "w")
classpathDOM.writexml(f)
print('Writing file:' + classpathFile)
finally:
f.close()
print('Done.')
I'm doing this to a few ANTLR grammars, which generate a Java parser using Ant. The Ant build script adds the #SuppressWarnings("all") to one Java file, and #Override to a few methods in another.
I can look up how it's done exactly, if you're interested.
In the case of ANTLR 2, it is possible to suppress warnings in generated code by appenidng #SuppressWarnings before the class declaration in the grammar file, e.g.
{#SuppressWarnings("all")} class MyBaseParser extends Parser;
This can be done by excluding certain directories from the build path (The following example is given using Eclipse 3.5)
[1] Bring up the Java Build Path
Click on the projectin Package Explorer
Right click, properties
Select Java Build Path
[2] Add directories to exclude
The Source tab should contain details of the project source folders
Expand the source folder and locate the 'Excluded:' property
Select 'Excluded:' and click Edit
Add folders into the Exclusion patterns using the Add/Add Multiple options
Click Finish, then ok for Eclipse to rebuild.
It's been a while since I have released the warning-cleaner plugin, and now that I am using Eclipse 3.8, I have no need for it anymore.
However, for those who still need this plugin, I have released it on github with the update site on bintray.
If you are still using Eclipse 3.7 or before, this could be useful.
Check this site for installation details.
If the eclipse project is generated from gradle using Eclipse plugin's eclipse command the Selectively ignore errors/warnings from source folders option can be set by adding this on the top level of you build.gradle file:
eclipse.classpath.file {
whenMerged { classpath ->
classpath.entries.each { entry ->
if (entry.path.contains('build/generated/parser')) {
entry.entryAttributes['ignore_optional_problems'] = true
}
}
}
}
This assumes that generated sources are in build/generated/parser folder.
Consider the following code:
// App.java
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.SimpleName;
public class App
{
public static void main(String[] args)
{
ASTVisitor visitor = new ASTVisitor()
{
public boolean visit(VariableDeclarationFragment node)
{
return false;
}
public boolean visit(SimpleName node)
{
return false;
}
};
}
}
compiled successfully with:
$ javac -cp org.eclipse.jdt.core.jar App.java
Library org.eclipse.jdt.core.jar is copied from the latest release of Eclipse. When running this program:
$ java App -cp org.eclipse.jdt.core.jar
I get the following runtime error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jdt/core/dom/ASTVisitor
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
...
Actually this is a stripped-down version of another test program where dependencies are managed with Maven, and giving the same error. Looking for a solution, I found hints that this may be related to missing dependencies, or dependencies not loaded in the correct order. However, I don't understand how this could be happening. Inspecting the used jar I get:
$ jar tf org.eclipse.jdt.core.jar | grep ASTVisitor
org/eclipse/jdt/core/dom/DefaultASTVisitor.class
org/eclipse/jdt/core/dom/ASTVisitor.class
org/eclipse/jdt/internal/compiler/ASTVisitor.class
so the actual class is indeed there. In addition to this, I tried loading a bunch of related classes, as suggested by this link, and then I tried again loading all JDT classes that come with the Eclipse installation, but unfortunately with no result.
What can be the problem and what else can I do to track it down?
Thank you very much.
The '-cp' option must be specified before the class you want to run on the 'java' command:
java -cp org.eclipse.jdt.core.jar App
Anything you put after the class name is just passed as a parameter to the program.
Thanks to greg-449 for spotting the command-line usage error. After fixing that, I was able to successfully run that example.
After some other trials, I found that, for some reason, these programs that use Eclipse JDT fail to run even after being successfully compiled, unless I add to the class path the jars directly taken from an actual Eclipse installation. This means that I could successfully run my program (the more complex one) compiled using Maven dependencies, after I added the Eclipse jars to the class path:
$ cd my-project/
$ mvn install
$ cd target
$ java -cp "myprogram.jar:../lib/*" path.to.my.main.Class
where lib contains a bunch of jars coming from my Eclipse installation.
EDIT
Actually it's not necessary to link Eclipse jar files at all. In fact everything works correctly when using maven-exec-plugin instead of directly call the java command:
$ mvn exec:java -Dexec.mainClass=path.to.my.main.Class
Thinking a bit about it, it seems now obvious that Maven automatically links the project dependencies' jar files, downloaded in ~/.m2 during the installation, when I call the command mvn exec:java. Probably I could have got the same result adding to the classpath the jars stored in ~/.m2 instead of manually copying those provided with my Eclipse installation.
I'm just starting to use Maven with my project. All of my production code is of course inside the main directory. As I add unit tests to my tests directory, is there a way to synchronize the main dir with my tests dir?
For example, say I add a new package org.bio.mynewpackage. I have to go in my main folder and add the same package name... this is rather annoying.
Any ideas?
Here is a Groovy Script embedded in a GMaven plugin execution. It does exactly what you are asking for.
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>mirror-folder-structure</id>
<phase>generate-test-sources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
<![CDATA[
static void createShadow(File base, File shadow){
if(base.exists()&&!shadow.exists())shadow.mkdirs();
base.eachDir { createShadow(it, new File(shadow, it.name))};
}
createShadow(pom.build.sourceDirectory,pom.build.testSourceDirectory);
]]>
</source>
</configuration>
</execution>
</executions>
</plugin>
The problem is: it won't run automatically. I have bound it to the phase generate-test-sources, but you can choose any other phase. You will however have to execute that phase manually, e.g. mvn generate-test-sources.
If you would however consider using Eclipse with the m2eclipse plugin, m2eclipse lets you define lifecycle phases that it runs automatically when you have saved a file, so that would be easier.
I don't know if I get your problem right: usually, by convention, maven will detect all class files in main/java and all class files in test/java. You don't have to declare the package names.
So if you add an new package an classes to "main", they will be compiled and packaged, if you add some new tests to "test", the will be autodiscovered and executed in the test phase.
Typically I would rely on the IDE to do this when I create tests.
Eg:
I create a new class org.bio.mynewpackage.MyNewClass in main/.
Now when I create a test org.bio.mynewpackage.MyNewClassTest, the IDE should automatically create the necessary directory tree.
I don't know if you were looking for something specific regards how maven might help you do this. Still i've always used rsync to match to target folders.
Something along the lines of:
rsync -Crit ./source ./target
where C ignores versioning
files/folders such as .svn
r is recursion i is information output.
t is timestamp. i've always put this
to ensure differences in files are
based on time stamp.
Add 'n' to run in test mode, it will output what will change rather than actually do it. Always do this first as rsync can totally mess things up if you don't have it right.
You can also add pattern matching rules, either in a file in each directory or once in the command line.
I don't know of any plugin that does this, but it should be pretty easy to write one. It could possibly even be done with some simple Groovy scripting using gmaven-plugin or the like.
Alternatively, this shell command should do what you want:
# ! -wholename '*/.*' excludes hidden dirs like .svn
$( cd src/main/java/ && find -type d ! -wholename '*/.*' -exec mkdir -p ../../test/java/{} \; )
EDIT:
Here's a simple Maven plugin (this plugin sorts entries of eclipse .classpath files by name) that should give you a quick start into Maven plugin development.
I'm using a parser generator that creates somewhat ugly code. As a result my Eclipse project has several dozen warnings emanating from generated source files. I know I can use the #SuppressWarning annotation to suppress particular warnings in particular elements, but any annotations I add by hand will be lost when the parser generator runs again. Is there a way to configure Eclipse to suppress warnings for a particular file or directory?
Starting with version 3.8 M6, Eclipse (to be exact: the JDT) has built-in functionality for this. It is configurable through a project's build path: Project properties > Java Build Path > Compiler > Source
Announced here: Eclipse 3.8 and 4.2 M6 - New and Noteworthy, called Selectively ignore errors/warnings from source folders. That's also where the screenshot is from. This is the new feature developed on the previously linked Bug 220928.
There is a ticket for this, Bug 220928, that has since been completed for Eclipse 3.8. Please see this answer for details.
If you're stuck with Eclipse 3.7 or lower: The user "Marc" commenting on that ticket created (or at least links to) a plugin called 'warningcleaner' in comment 35. I'm using that with a lot of success while waiting for this feature to be integrated into Eclipse.
It's really quite simple:
Install plugin.
Right-click project and select "Add/remove generated code nature".
Open the project settings (right-click and select "properties").
Open the tab 'Warning Cleaner'.
Select the source folders you want to ignore the warnings from.
I solved this by using the maven regexp replace plugin - it does not solve the cause, but heals the pain:
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>maven-replacer-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>target/generated-sources/antlr/**/*.java</include>
</includes>
<regex>true</regex>
<regexFlags>
<regexFlag>MULTILINE</regexFlag>
</regexFlags>
<replacements>
<replacement>
<token>^public class</token>
<value>#SuppressWarnings("all") public class</value>
</replacement>
</replacements>
</configuration>
</plugin>
Note that I did not manage to get the ** notation to work, so you might have to specify path exactly.
See comment below for an improvement on how not to generate duplicate #SupressWarnings
I think the best you can do is enable project specific settings for displaying warnings.
Window -> Preferences -> Java -> Compiler -> Errors/Warnings
On the top of the form is a link for configuring project specific settings.
User #Jorn hinted at Ant code to do this. Here's what I have
<echo>Adding #SuppressWarnings("all") to ANTLR generated parser/lexer *.java</echo>
<echo> in ${project.build.directory}/generated-sources/antlr/</echo>
<replace dir="${project.build.directory}/generated-sources/antlr/"
summary="true"
includes="**/*.java"
token="public class"
value='#SuppressWarnings("all") public class' />
Note that Ant's <replace> does text replacement, not regular expression replacement,
so it cannot use the ^ meta-character in the token to match beginning of line as the maven regexp replace plugin does.
I'm doing this at the same time that I run Antlr from maven-antrun-plugin in my Maven pom, because the ANTLR maven plugin did not play well with the Cobertura maven plugin.
(I realize this is not an answer to the original question, but I can't format Ant code in a comment/reply to another answer, only in an answer)
I don't think Eclipse inherently provides a way to do this at the directory level (but I'm not sure).
You could have the generated files go into a separate Java project, and control warnings for that specific project.
I generally prefer to place automatically-generated code in a separate project anyway.
You can only suppress warnings at the project level. However, you can configure your problems tab to suppress warnings from files or packages. Go into the Configure Contents menu and work with the "On working set:" scope.
This small python script "patches" the M2E-generated .classpath files and adds the required XML tag to all source folders starting with target/generated-sources. You can just run it from you project's root folder. Obviously you need to re-run it when the Eclipse project information is re-generated from M2E. And all at your own risk, obviously ;-)
#!/usr/bin/env python
from xml.dom.minidom import parse
import glob
import os
print('Reading .classpath files...')
for root, dirs, files in os.walk('.'):
for name in files:
if (name == '.classpath'):
classpathFile = os.path.join(root, name)
print('Patching file:' + classpathFile)
classpathDOM = parse(classpathFile)
classPathEntries = classpathDOM.getElementsByTagName('classpathentry')
for classPathEntry in classPathEntries:
if classPathEntry.attributes["path"].value.startswith('target/generated-sources'):
# ensure that the <attributes> tag exists
attributesNode = None;
for attributes in classPathEntry.childNodes:
if (attributes.nodeName == 'attributes'):
attributesNode = attributes
if (attributesNode == None):
attributesNode = classpathDOM.createElement('attributes')
classPathEntry.appendChild(attributesNode)
# search if the 'ignore_optional_problems' entry exists
hasBeenSet = 0
for node in attributesNode.childNodes:
if (node.nodeName == 'attribute' and node.getAttribute('name') == 'ignore_optional_problems'):
# it exists, make sure its value is true
node.setAttribute('value','true')
#print(node.getAttribute('name'))
hasBeenSet = 1
if (not(hasBeenSet)):
# it does not exist, add it
x = classpathDOM.createElement("attribute")
x.setAttribute('name','ignore_optional_problems')
x.setAttribute('value','true')
attributesNode.appendChild(x)
try:
f = open(classpathFile, "w")
classpathDOM.writexml(f)
print('Writing file:' + classpathFile)
finally:
f.close()
print('Done.')
I'm doing this to a few ANTLR grammars, which generate a Java parser using Ant. The Ant build script adds the #SuppressWarnings("all") to one Java file, and #Override to a few methods in another.
I can look up how it's done exactly, if you're interested.
In the case of ANTLR 2, it is possible to suppress warnings in generated code by appenidng #SuppressWarnings before the class declaration in the grammar file, e.g.
{#SuppressWarnings("all")} class MyBaseParser extends Parser;
This can be done by excluding certain directories from the build path (The following example is given using Eclipse 3.5)
[1] Bring up the Java Build Path
Click on the projectin Package Explorer
Right click, properties
Select Java Build Path
[2] Add directories to exclude
The Source tab should contain details of the project source folders
Expand the source folder and locate the 'Excluded:' property
Select 'Excluded:' and click Edit
Add folders into the Exclusion patterns using the Add/Add Multiple options
Click Finish, then ok for Eclipse to rebuild.
It's been a while since I have released the warning-cleaner plugin, and now that I am using Eclipse 3.8, I have no need for it anymore.
However, for those who still need this plugin, I have released it on github with the update site on bintray.
If you are still using Eclipse 3.7 or before, this could be useful.
Check this site for installation details.
If the eclipse project is generated from gradle using Eclipse plugin's eclipse command the Selectively ignore errors/warnings from source folders option can be set by adding this on the top level of you build.gradle file:
eclipse.classpath.file {
whenMerged { classpath ->
classpath.entries.each { entry ->
if (entry.path.contains('build/generated/parser')) {
entry.entryAttributes['ignore_optional_problems'] = true
}
}
}
}
This assumes that generated sources are in build/generated/parser folder.
We have a git repository which contains source for a few related Java WARs and JARs. It would be nice if the Java code could somehow:
System.err.println("I was built from git commit " + commitID);
(Obviously real code might be putting this into an HTTP header, logging it on startup, or whatever, that's not important right now)
We are using Ant to build (at least for production builds, it seems some programmers do their testing from inside Eclipse which I know even less about) binaries.
Is there a canonical way to get the commit id for the current git checkout into our Java at build time? If not, can people using Ant to build suggest how they'd do it and we'll see if a canonical solution emerges? I'm sure I can invent something myself entirely from whole cloth, but this seems like a re-usable building block, so I'd rather not.
You can get the last commit SHA with
git rev-parse HEAD
but it's generally a lot more useful to use
git describe
which will give you something that looks like this:
v0.7.0-185-g83e38c7
This works if you have tags - it will tell you how many commits from the last valid tag your current checkout is at plus a partial SHA for that commit, so you can use it to base a checkout off of later. You can use this identifier just like a SHA in most circumstances, but it's much more human readable.
I don't know if there are any Ant task for git (I googled a bit without success), anyway Ant can update a properties file with Piotr's option (git rev-parse HEAD) and then in runtime use that properties to get the revision number. This is cleaner and IDE friendly than having Ant generating a .java file.
If it helps for someone else. I know yours is ANT
For MAVEN build, you could probably use git-commit-id-plugin in your pom.xml file
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.0</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
</configuration>
</plugin>
Please go through :
1. http://www.baeldung.com/spring-git-information &
2. https://github.com/ktoso/maven-git-commit-id-plugin for more info.
I wrote an Ant task to get the buildnumber using JGit API (without git command line app), see jgit-buildnumber-ant-task. Then you can store this buildnumber inside MANIFEST.MF file and get it from the classpath on runtime.
git rev-parse HEAD will print what you probably want (e.g. id of HEAD commit).
You can make ant generate a simple Java class with this id as a static constant.
First, you can use ident gitattribute with $Id$ keyword (although it is not probably what you want; it is hash of file contents, and has nothing to do with current project version).
Second, you can do it the way Linux kernel and Git itself do it: in Makefile (in your case: in Ant file) there is rule which replaces some placeholder, usually '##VERSION##' (but in case of Perl it is '++VERSION++') by result of GIT-VERSION-GEN, which in turn uses "git describe". But for that to be useful you have to tag your releases (using annotated / signed tags).