wood burning stoves 2.0*
The moose likes Java in General and the fly likes ARGH!   Package problem while using * Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of EJB 3 in Action this week in the EJB and other Java EE Technologies forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "ARGH!   Package problem while using *" Watch "ARGH!   Package problem while using *" New topic
Author

ARGH! Package problem while using *

Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

I hope I will not anger or hurt some Java beginners with this post, and it's not like I'm an old hand yet either... but I'm feeling really steamed and like I belong back in Java kindergarten.

I cannot understand what is happening, here is some source:
This compiles nicely, and I then place it here:
d:\javawork\com\qunara\util\StringReplace.class
I make another java class to test my StringReplace class, and I save it under d:\javawork
This will not compile, I get this error:This leads me to believe that my classpath (which is .) is fine, and that the import is successful. Because it's not a classDefNotFound error, it's a "I can't find this method signature" error. But this is nuts, because that method is certainly there.
If I replace the * in the import with the actual class name: Then everything runs beautifully, and I get my output:
This is VERY frustrating. Does anyone have an idea? p.s. I've tried jar'ing the class file, no change.

[This message has been edited by Mike Curwen (edited June 26, 2001).]
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

I'm not sure if import takes precedence over classpath when resolving names but are you sure there's no other StringReplace.class that's also in you classpath? Maybe the compiler is finding an older or unrelated class that just happens to have the same name.


Junilu - [How to Ask Questions] [How to Answer Questions]
Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

I had thought of that, so I deliberately used
javac - classpath . TestReplacePackage.java

But also, this can't really be the cause for another reason.

If there is a naming conflict, the compiler should complain, instead of attempting to use 'the wrong one' or 'the first one it finds' produces:So if there is an old class kicking around with the same name, I'd expect this kind of error (wouldn't I?) And besides, I can assure you there is no older class.

In fact, I did get this to work (sort of) but it is sloppy and I can't figure out why I need to do what I'm doing...
But why oh why did I need to fully qualify my StringReplace class when I attempt to use it, if I have successfully imported it with the * notation? I say successfully, because it doesn't complain with a ClassDefNotFound error.

Still frustrating!

[This message has been edited by Mike Curwen (edited June 26, 2001).]
[This message has been edited by Jim Yingst (edited June 27, 2001).]
Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

Well... I got it to work another way, and now I'm *totally* confused.

I wanted to confirm my thoughts about the error message, so I did this:And I got the same "cannot resolve symbol" error for the Date constructor with an Integer (which was expected, because there's no such constructor. So the import of the java.util.Date succeeded, but I was just using it wrong. So too, am I 'apparently' using my own class wrong.

So I thought to myself... "This can't be right.. maybe it's the compiler". So I dropped down a version and tried to compile it with 1.2.2 and I got this intriguing error:Well umm... I guess my TestReplacePackage file (my driver) was in the unnamed package... so I did this:
Merely by packaging my driver application, it now compiles with the * import. What the ^*#$&%*#(* is going on?

And one last thing that is making me wonder... shouldn't I have gotten a more graceful error message for my new Date(Integer(21))? Shouldn't it have read something like: "Cannot convert java.lang.Integer into java.lang.String", or "expected: java.lang.String \n found: java.lang.Integer"

Maybe it *is* my compiler. ARgh. Time to go home and sleep on it.

[This message has been edited by Mike Curwen (edited June 26, 2001).]
[This message has been edited by Jim Yingst (edited June 27, 2001).]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
My guess is that you had an old .class file that wasn't being regenerated. When you compile with
javac - classpath . TestReplacePackage.java
you are telling the compiler to comile that particular file, and any other files it needs to in order to have all the necessary class files. So when the compiler discovers a reference to the StringReplace class within TestReplacePackage.java, it looks for that class. Key point here - if there is a .class file or .jar file with the appropriate class and a .java file, the compiler does not check dates to see if the .java is newer than the .class, indicating it should recompile. Instead it will simply use the old .class file. I'm not sure if it always uses a class file if available, or if it uses whichever it finds first. I think it's the latter, but you should test to see. This sort of thing can vary from compiler to compiler anyway, I believe.
So in your case, you probably had an old class file for StringReplace which did not define a swap(String, String, String) method, and the compiler never recompiled that file until you forced it to with your name change. To avoid this in the future, I recommend you compile using the -d option to put executables in a separate directory tree from the source code. Then you can tune your class path to make sure that the compiler finds .java files before .class files. If this doesn't work, you can go one step further and delete all the executables before compiling (much easier when they're in a separate directory tree) . This way you're sure to regenerate everything.
Alternately, you can use make files (on Unix at least) to manage these problems in a more sopisticated fashion, or use an IDE which takes care of this for you. Personally I use JBuilder almost all the time now, and it almost never has a problem. Occasionally I confuse the sytem by editing a file using some other editor besides JBuilder's, and JBuilder may not notice the change. At this point I just delete all my executables and recompile. Works like a charm.


"I'm not back." - Bill Harding, Twister
Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

Jim, I admit, at first I thought your experience with IDE's was showing...

Because I thought only IDE's were 'smart' enough to compile dependencies, not plain old javac:
<pre>javac - classpath . TestReplacePackage.java</pre>
you are telling the compiler to comile that particular file, and any other files it needs to in order to have all the necessary class files.
This is (in my mind) bad behaviour. Because let's say all my source files are in the same directory. If I import a certain class, and the source for that imported class is in the current directory, then that *.java would get turned into a *.class, and then THAT (improperly placed because I don't use -d) *.class file would be used.

It was not a matter of there being an old class file, as you suggested. I can assure you that I recompiled the class and moved the file to the proper directory. It was that my source for this class was in the same directory as my driver class.

You said:
Key point here - if there is a .class file or .jar file with the appropriate class and a .java file, the compiler does not check dates to see if the .java is newer than the .class, indicating it should recompile. Instead it will simply use the old .class file. I'm not sure if it always uses a class file if available, or if it uses whichever it finds first. I think it's the latter, but you should test to see. This sort of thing can vary from compiler to compiler anyway, I believe.

In fact, the compiler will not use the class file in any event, if there is a *.java file of the appropriate name in the current directory. If it finds a *.java file with that name, it will recompile it... At least both jdk1.1.8 and jdk1.2.2 do this. jdk1.3 does not, but it still throws an error, so it still seems confused by the presence of the source file.
I recommend you compile using the -d option to put executables in a separate directory tree from the source code. Then you can tune your class path to make sure that the compiler finds .java files before .class files.
In my case, it seems that finding the *.java file before the *.class file was the whole problem. It was the fact that my imported class's source file was in the classpath. But I see what you mean. If I used -d, the recompiled (completely unnecessarily) class file would be moved before the importing class is compiled. But I still don't like the behaviour of recompiling the imported classes. It should attempt the import first, and it would find the right class file ready and waiting for it, and not need to recompile the *.java source. ie: Note to Sun: compile *only* what I tell you to compile.

Thanks for your help.

p.s. I had used this method so many times before... but when I really think about it, I realize that all my packaged classes source files where always in a folder somewhere else, and not at the same directory level as my driver classes, or the classes that did the importing.

p.p.s. I do use an IDE (in fact JBuilder), but for "simple" things (haha) I like to use TextPad. The whole "make new project, yadda, yadda" seems like a waste of time if all i want to do is write a small utility class. I guess I also like to keep myself aware of command lines, because around my job, IDE's are thought of as "sigh... if you really *need* to use one i guess it's ok."

[This message has been edited by Jim Yingst (edited June 27, 2001).]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Mike - I edited several of your posts because of overlong lines. What I mean is, any time you use [ code ], [ quote ], or < pre > tags, if you include a really long line inside that tag, the system will not supply any line breaks, and you effectively force the entire page (all the other posts as well) to be as long as that line. Which means that you need to keep using the horizontal scroll bear to see anything, which I find annoying. So I inserted line breaks in some of your posts, and in other cases replaced [ code ] with [ quote ] tags. Hope you don't mind.
I feel musch the same as you about IDE's in general - I only converted over to JBuilder when I was dealing with a large code base, and got tired of searching through subdirectories for a given class. Now the class I need is usually just a click or two away. Previously I used .bat files (yes, I'm on NT) to handle compilation - I'd spend some time tweaking all the options to be just what I wanted, and then I could recompile fairly easily. That way you can always see exactly what command-line options are being used. I still revert to the command line periodically, particularly when I need to work on Unix. But I tend to do as much of my development as possible on the NT box, and only switch over when I have to.
There are a lot of ways javac can do unexpected things if you're not careful, as you've discovered. (Or even if you are being careful, but just don't realize what the compiler is doing.) Not the most user-friendly of tools, I'm afraid. But once you get it set up just right, it tends to work well enough.
Mike Curwen
Ranch Hand

Joined: Feb 20, 2001
Posts: 3695

Jim, I don't mind at all.. I knew what my (now next to) last post had done, but I didn't bother fixing it.. I copy and pasted from the web browser, a few quotes from your previous post. Because the pasted text didn't have line breaks, it went super long. And I didn't 'reply quoted' and I didn't use the quote blocks, instead putting them in code blocks because UBB is buggy with the [ quote ] ones. Check my rant in the 'JavaRanch Forum' forum.
krishna valavala
Greenhorn

Joined: Mar 06, 2002
Posts: 10
I know it is too late to reply to this message. But I just happened to stumble on this message, so I thought I will reply to it anyway.
Java stopped supporting inter-mixing of files in package and those in unnamed package. Specifically suppose you have a file A.java which has no package statement and you have another file B.java which has the following statement package somepackage; Then you cannot access A.java from B.java. Some earlier versions of java allowed it though.
Krishna
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: ARGH! Package problem while using *
 
Similar Threads
.NoClassDefFoundError in NetBeans, fine on command line
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") not working !
File Question
deep copy of vector
String replaceAll function error