Bug 52096 - Add an option to <javac> to suppress creation of package-info.class
Summary: Add an option to <javac> to suppress creation of package-info.class
Status: RESOLVED FIXED
Alias: None
Product: Ant
Classification: Unclassified
Component: Core tasks (show other bugs)
Version: 1.8.2
Hardware: PC Windows XP
: P2 enhancement (vote)
Target Milestone: 1.8.3
Assignee: Ant Notifications List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-27 10:22 UTC by Praveen
Modified: 2012-03-12 16:27 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Praveen 2011-10-27 10:22:50 UTC
If the packages are created directly under the source directory for JAVAC,then the logic for creating empty package-info.class would be right.

But in case there are sub-folders inside the source directory for JAVAC,then the logic for detecting the packages includes the sub-folders and hence the empty package-info.class gets always created and also created with the subfolders included in the destination directory of JAVAC.

I think the removeleading path method in FileUtils class removes the leading path till the source directory ,but if there are sub-folders under the source directory ,this method cannot remove the same.

Suppose for example:

If I have a folder structure

->src
  -->java
    --->fld1
        package:com.apache.test1
    --->fld2
        package:com.apache.test2

Suppose the source directory to JAVAC is "src/java".I have a package-info.java file inside package "com.apache.test1".Suppose the destination directory is build/classes.If I run JAVAC task using ant 1.8.2 ,it creates an empty package-info.class in build/classes/fld1/com/apache/test1.
The problem seems to be in the construction of the packageinfo map and the usage of removeleadingpath in the fileutils class.
Comment 1 Stefan Bodewig 2011-10-27 12:42:53 UTC
Your src shouldn't be "src/java" but you should be using multiple source directories - one per "fld".

If you use a single srcdir javac's logic of whether it needs to recompile a class or not is going to fail as well.
Comment 2 Praveen 2011-10-27 14:42:20 UTC
But javac allows users to specify in this way.User's can take call whether they want to recompilation check to happen or not.
For example : If we do not want a recompilation check ,all classes previously generated are cleaned before building it again ,in that case the user need not provide multiple source directories.Anyway to me if javac allows ,then ANT's JAVAC task should also support creating the package-info classes the same way.
Comment 3 Stefan Bodewig 2011-10-28 09:32:25 UTC
Yes, javac allows users to use it that way, but then it does unexpected things like creating package-info.class files in wrong places ;-)

The package-info.class is only created for the purpose of tracking what needs to get recompiled.  If you deliberately break that there isn't anything Ant can do (it doesn't know the package name as it assumes you structure follows best practices).

In a case like yours the only thing we could do was to offer an attribute that suppresses the generation of empty package-info.class files completely.  I don't expect this will be widely used, though.
Comment 4 Praveen 2011-10-28 09:50:28 UTC
(In reply to comment #3)
> Yes, javac allows users to use it that way, but then it does unexpected things
> like creating package-info.class files in wrong places ;-)
> The package-info.class is only created for the purpose of tracking what needs
> to get recompiled.  If you deliberately break that there isn't anything Ant can
> do (it doesn't know the package name as it assumes you structure follows best
> practices).
> In a case like yours the only thing we could do was to offer an attribute that
> suppresses the generation of empty package-info.class files completely.  I
> don't expect this will be widely used, though.

I do have different views on it ,"Best practice" for a project folder structure is very specific to each and every project and a very relative term.

Yes suppressing it would atleast make it behave the way the earlier versions (1.7.X) used to behave.I am sure "javac" by itself would come with a solution for the problem that you were trying to solve in ANT 1.8.X and then anyway this feature in ANT need not be used.I hope its already there in the latest versions of the JDK.

Yes suppressing option would surely help.:)
Comment 5 Stefan Bodewig 2011-10-28 10:10:58 UTC
I really don't want to argue the best practice term here, one last note:  Of course the folder structure is best determnied by the project but you should tell Ant about it.  So rather than 

<javac src="src/java" .../>

use

<javac ...>
  <src>
    <pathelement location="src/java/fld1"/>
    <pathelement location="src/java/fld2"/>
  </src>
</javac>

or a dirset nested into src if you want to keep it dynamic.

It's not that Ant wants to enforce a structure, it just needs understanding the one you use.

Back to the topic at hand: the class file created really only is there for Ant, not javac.  Some package level annotations don't create anything in class files so Ant will always recompile the package-info.java files unless it creates them itself - something you don't care about.

I'll turn this into an enhancement request, change the subject and look into implementing it.
Comment 6 Praveen 2011-10-28 10:16:58 UTC
(In reply to comment #5)
> I really don't want to argue the best practice term here, one last note:  Of
> course the folder structure is best determnied by the project but you should
> tell Ant about it.  So rather than 
> <javac src="src/java" .../>
> use
> <javac ...>
>   <src>
>     <pathelement location="src/java/fld1"/>
>     <pathelement location="src/java/fld2"/>
>   </src>
> </javac>
> or a dirset nested into src if you want to keep it dynamic.
> It's not that Ant wants to enforce a structure, it just needs understanding the
> one you use.
> Back to the topic at hand: the class file created really only is there for Ant,
> not javac.  Some package level annotations don't create anything in class files
> so Ant will always recompile the package-info.java files unless it creates them
> itself - something you don't care about.
> I'll turn this into an enhancement request, change the subject and look into
> implementing it.

Thanks a lot for your patience hearing me :).
I will surely have a look into all the work arounds and see how feasible it would be right now for my work.Thanks once again.
Comment 7 Stefan Bodewig 2011-10-28 10:44:54 UTC
createMissingPackageInfoClass attribute added with svn revision 1190243
Comment 8 Jesse Glick 2011-10-28 14:39:55 UTC
A fix for the originally stated problem would be for lookForPackageInfos to read the actual "package com.apache.test1;" line in package-info.java, as javac itself would. One reason the code does not already do this is out of concern over handling of non-ASCII characters in the package name and potential interaction with the filesystem. But I suppose it would work to just read package-info.java using the same encoding being passed to javac.

Additionally, it is just easier to strip off a path prefix than to parse a general source file including comments, annotations, and/or import statements. In practice, it is overwhelmingly likely that the package statement is on a line by itself, and that there is not something that looks like a package statement inside a block comment. There must be exactly one package statement in a package-info.java, so it would almost always suffice to look for lines of the form

^\s*package\s+(\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*(?:[.]\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*)*)\s*;\s*$

and use \1 if exactly one such is found, falling back to the current logic otherwise. This would only be fooled by pathological cases such as

/*
package fake;
*/
package
real;

or the use of \uXXXX escapes.
Comment 9 Praveen 2011-10-30 10:08:58 UTC
I agree with you...But this issue seems to have been already resolved and closed and I am not sure how this this needs to be addressed
Comment 10 Stefan Bodewig 2011-10-31 06:15:50 UTC
(In reply to comment #8)
> A fix for the originally stated problem would be for lookForPackageInfos to
> read the actual "package com.apache.test1;" line in package-info.java, as javac
> itself would.

Sure, this could work.

Isn't the whole point of creating the package-info.class files to avoid the overhead of running javac on the source files?  Wouldn't opening each package-info.java file and scanning it with some regexp take almost as long as simply passing the files to javac in the end?  These are honest questions.

Stefan
Comment 11 Jesse Glick 2011-11-10 00:06:33 UTC
(In reply to comment #10)
> Wouldn't opening each
> package-info.java file and scanning it with some regexp take almost as long as
> simply passing the files to javac in the end?

Probably depends on the situation. While javac itself is reasonably fast on small files, i.e. not much slower than the I/O of loading the file, running javac incurs two kinds of additional cost:

1. Opening any classpath entries, which may be numerous and/or large.

2. Running any annotation processors, which could be slow.
Comment 12 Stefan Bodewig 2011-11-11 14:29:34 UTC
If we modified the task as you describe we'd trade decreased performance for all users (who have a package-info.java files) for not generating empty package-info.class files in non-existant packages for the very few users who prefer to run javac in a way that it cannot guess the package hierarchy.

Doesn't sound attractive to me.
Comment 13 Jesse Glick 2011-11-11 19:31:53 UTC
(In reply to comment #12)
> Doesn't sound attractive to me.

OK. Would be significantly more work anyway.
Comment 14 Jesse Glick 2012-03-12 16:27:15 UTC
BTW if we can detect that JDK 7 javac is being used we could pass -Xpkginfo:always instead of the current behavior of createMissingPackageInfoClass=true.