As we know that the package statement is when triggered by the javac command, it creates the related directories according to the package name.
For example:
// MyClassB.java
package abc.xyz;
class MyClassA{
// ...
}
class MyClassB{
// ...
}
Now when I compile this file:
javac -d . MyClassB.java
After compilation, we will have the following directory structure having the .class files.
/
|___ abc
|___ xyz
|___ MyClassA.class
|___ MyClassB.class
Now the question is that, are these MyClassA.class and MyClassB.class contains only the MyClassA and MyClassB class's compiled bytecode?
What about the following statement?
package abc.xyz;
Is that statement removed during the compilation? Or this statement is only removed from the MyClassA class and remains in the MyClassB class because the name of the file was MyClassB.java. Or maybe the MyClassB.class file only contains the MyClassB class bytecode after compilation and the package abc.xyz; is removed during the compilation as well? If package abc.xyz; is not removed at the compilation time then it would be the problem when we will use this file at runtime because the runtime engine will also trigger the package abc.xyz; statement bytecode version, so, it would be a problem. Or it is removed during the compilation? Or the bytecode is only created for the classes but not for the file which contains the package abc.xyz; statement which results that package abc.xyz; is not become the part of the .class files.
The picture below clearly explains the question:
Can anyone explain what is the scenario behind this? It is my humble request to the contributors to not negative mark my question because i have some confusions regarding java, so, i want to clear my concept.If still my question is able for negative mark, then its Ok do, but at least answer as well.
Thanks !!!
Directives like the package declaration, as well as import statements, do not generate any code at all, they only affect how the compiler will treat names within the same compilation unit.
So a declaration like
package abc.xyz;
public class MyClassA {
}
creates a class with the qualified name abc.xyz.MyClassA or a class with the simple name MyClassA within the package abc.xyz; both means the same.
The qualified name is stored within the .class file, which is the only relevant information to the JVM.
There is the convention to store such file as SimpleName.class within a directory derived from the package name, i.e. abc/xyz/MyClassA.class, adhered by javac and used by the standard class loaders to look up the file when a class of that name is requested. Obviously, having such a convention makes life easier.
In principle, other storage methods are possible and there are some known. Starting with Java 9, the reference implementation has a module image format, before that, there was the “shared class data archive”, further, there was “Pack200”, an archive format that has been deprecated for removal with JDK 11.
Note that even jar files, which are extended zip files, are not exactly what you see. A zip file consist of a linear sequence of file entries having a qualified name, so in your case, you would have two entries reporting their names as abc/xyz/MyClassA.class and abc/xyz/MyClassB.class, whereas any directory structure shown by tools is actually derived from these names and does not implies that nested entries for abc and xyz actually exist. Still, the standard class loader will also use these entries the same way as if this directory structure existed, so there is no problem with the mindset of having stored the directory structure into the zip/jar file.
But starting with Java 9, there can be different versions for the same class, to be selected depending on the current Java version. The naming scheme used for that is not part of the convention used by javac when storing the files.
It does not go anywhere, it is compiled as class abc.xyz.MyClassA. You can see that if you would decompile that .class for example using javap.
If you open the .class file of any of your class than you can see the package details inside that. In your case if you will open MyClassA.class in text editor, then you can see something like abc/xyz/MyClassA. The the JVM will use it like abc.xyz.MyClassA. That's the reason if we need to use this class in some other class, we need to use it like import abc.xyz.MyClassA.
Related
I'm getting the following error whilst trying to obfuscate my Java program (A spigot API plugin for a minecraft server)
Note: you're writing the processed class files to a directory [C:\Users\user\Desktop\OBFUSCATE\out].
This will likely cause problems with obfuscated mixed-case class names.
You should consider writing the output to a jar file, or otherwise
specify '-dontusemixedcaseclassnames'.
Reading program jar [C:\Users\user\Desktop\OBFUSCATE\pvptimer.jar]
Reading library jar [C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar]
Reading library jar [C:\Users\user\Desktop\OBFUSCATE\paper-1613.jar]
Warning: class [META-INF/versions/9/com/destroystokyo/paperclip/Main.class] unexpectedly contains class [com.destroystokyo.paperclip.Main]
Note: duplicate definition of library class [com.destroystokyo.paperclip.Main]
Warning: class [META-INF/versions/9/com/destroystokyo/paperclip/Agent.class] unexpectedly contains class [com.destroystokyo.paperclip.Agent]
Note: duplicate definition of library class [com.destroystokyo.paperclip.Agent]
Reading library jar [C:\Users\user\Desktop\OBFUSCATE\patched_1.12.2.jar]
Note: duplicate definition of library class [org.json.simple.ItemList]
Note: duplicate definition of library class [org.json.simple.JSONArray]
Note: duplicate definition of library class [org.json.simple.JSONAware]
Note: duplicate definition of library class [org.json.simple.JSONObject]
Note: duplicate definition of library class [org.json.simple.JSONStreamAware]
Note: duplicate definition of library class [org.json.simple.JSONValue]
Note: duplicate definition of library class [org.json.simple.parser.ContainerFactory]
Note: duplicate definition of library class [org.json.simple.parser.ContentHandler]
Note: duplicate definition of library class [org.json.simple.parser.JSONParser]
Note: duplicate definition of library class [org.json.simple.parser.ParseException]
Note: duplicate definition of library class [org.json.simple.parser.Yylex]
Note: duplicate definition of library class [org.json.simple.parser.Yytoken]
Note: there were 14 duplicate class definitions.
(http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)
Warning: there were 2 classes in incorrectly named files.
You should make sure all file names correspond to their class names.
The directory hierarchies must correspond to the package hierarchies.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)
If you don't mind the mentioned classes not being written out,
you could try your luck using the '-ignorewarnings' option.
Please correct the above warnings first.
I'm just not sure how to fix this error. I have looked and found several online tutorials claiming to be able to fix this issue but to no avail.
If anyone has run into this issue and has been able to fix it, please share your wisdom!
Edit**:
After selecting the box Ignore warnings about possibly erroneous input, the obfuscation goes through, but upon loading the plugin, I get this error:
This is most likely due to the libraries your code that you are obfuscating depends on, or that other code in your project depends on your now-obfuscated code however its references are pointing to the method names of the unobfuscated jar.
Let me know if that one flew past your head, I will try to explain it a bit better if I can.
A small example:
OldClass { //This class, has reference to LibClass.callMethod
void oldMethod() {
LibClass.callMethod();
}
}
LibClass {
static void callMethod() {
//now if this gets obfuscated,
//and the above code is never renamed to this new obfuscated name
// you will get errors like you are seeing (The method doesn't exist anymore)
}
}
If one writes two public Java classes with the same case-insensitive name in different directories then both classes are not usable at runtime. (I tested this on Windows, Mac and Linux with several versions of the HotSpot JVM. I would not be surprised if there other JVMs where they are usable simultaneously.) For example, if I create a class named a and one named A like so:
// lowercase/src/testcase/a.java
package testcase;
public class a {
public static String myCase() {
return "lower";
}
}
// uppercase/src/testcase/A.java
package testcase;
public class A {
public static String myCase() {
return "upper";
}
}
Three eclipse projects containing the code above are available from my website.
If try I calling myCase on both classes like so:
System.out.println(A.myCase());
System.out.println(a.myCase());
The typechecker succeeds, but when I run the class file generate by the code directly above I get:
Exception in thread "main" java.lang.NoClassDefFoundError: testcase/A (wrong name: testcase/a)
In Java, names are in general case sensitive. Some file systems (e.g. Windows) are case insensitive, so I'm not surprised the above behavior happens, but it seems wrong. Unfortunately the Java specifications are oddly non-commital about which classes are visible. The Java Language Specification (JLS), Java SE 7 Edition (Section 6.6.1, page 166) says:
If a class or interface type is declared public, then it may be accessed by
any code, provided that the compilation unit (§7.3) in which it is declared is
observable.
In Section 7.3, the JLS defines observability of a compilation unit in extremely vague terms:
All the compilation units of the predefined package java and its subpackages lang
and io are always observable. For all other packages, the host system determines which compilation units are observable.
The Java Virtual Machine Specification is similarly vague (Section 5.3.1):
The following steps are used to load and thereby create the nonarray class or
interface C denoted by [binary name] N using the bootstrap class loader [...]
Otherwise, the Java virtual machine passes the argument N to an invocation of a
method on the bootstrap class loader to search for a purported representation of C
in a platform-dependent manner.
All of this leads to four questions in descending order of importance:
Are there any guarantees about which classes are loadable by the default class loader(s) in every JVM? In other words, can I implement a valid, but degenerate JVM, that won't load any classes except those in java.lang and java.io?
If there are any guarantees, does the behavior in the example above violate the guarantee (i.e. is the behavior a bug)?
Is there any way to make HotSpot load a and A simultaneously? Would writing a custom class loader work?
Are there any guarantees about which classes are loadable by the bootstrap class loader in every JVM?
The core bits and pieces of the language, plus supporting implementation classes. Not guaranteed to include any class that you write. (The normal JVM loads your classes in a separate classloader from the bootstrap one, and in fact the normal bootstrap loader loads its classes out of a JAR normally, as this makes for more efficient deployment than a big old directory structure full of classes.)
If there are any guarantees, does the behavior in the example above violate the guarantee (i.e. is the behavior a bug)?
Is there any way to make "standard" JVMs load a and A simultaneously? Would writing a custom class loader work?
Java loads classes by mapping the full name of the class into a filename that is then searched for on the classpath. Thus testcase.a goes to testcase/a.class and testcase.A goes to testcase/A.class. Some filesystems mix these things up, and may serve the other up when one is asked for. Others get it right (in particular, the variant of the ZIP format used in JAR files is fully case-sensitive and portable). There is nothing that Java can do about this (though an IDE could handle it for you by keeping the .class files away from the native FS, I don't know if any actually do and the JDK's javac most certainly isn't that smart).
However that's not the only point to note here: class files know internally what class they are talking about. The absence of the expected class from the file just means that the load fails, leading to the NoClassDefFoundError you received. What you got was a problem (a mis-deployment in at least some sense) that was detected and dealt with robustly. Theoretically, you could build a classloader that could handle such things by keeping searching, but why bother? Putting the class files inside a JAR will fix things far more robustly; those are handled correctly.
More generally, if you're running into this problem for real a lot, take to doing production builds on a Unix with a case-sensitive filesystem (a CI system like Jenkins is recommended) and find which developers are naming classes with just case differences and make them stop as it is very confusing!
Donal's fine explanation leaves little to add, but let me briefly muse on this phrase:
... Java classes with the same case-insensitive name ...
Names and Strings in general are never case-insensitive in themselves, it's only there interpretation that can be. And secondly, Java doesn't do such an interpretation.
So, a correct phrasing of what you had in mind would be:
... Java classes whose file representations in a case-insensitive file-system have identical names ...
I tried to add or remove a character from one of the class names and it worked. I feel it's always better to use different class names.
Don't think just about folders.
Use explicit different namespaces ("packages") for your classes, and maybe use folders to match your classes.
When I mention "packages", I don't mean "*.JAR" files, but, just the concept of:
package com.mycompany.mytool;
// "com.mycompany.mytool.MyClass"
public class MyClass
{
// ...
} // class MyClass
When you do not specify a package for your code, the java tools (compiler, I.D.E., whatever), assume to use the same global package for all. And, in case of several similar classes, they have a list of folders, where to look for.
Packages are like "virtual" folders in your code, and apply to all your packages on your classpath, or installation of Java. You can have several classes, with the same I.D., but, if they are in different package, and you specify which package to look for, you won't have any problem.
Just my 2 cents, for your cup of Java coffe
In my Java application, I use a third-party library.
However, I found something strange, there are some nested packages, and some classes whose name may be the same as the name of the package.
I am afraid I can not make it clear. Here is an example:
package
com.xx.a
com.xx.a.a
And there is a class named 'a' inside the 'com.xx.a'.
So if I want to call this class 'a'...
I write:
a ma = new com.xx.a.a();
Then the IDE will think that I mean the package 'com.xx.a.a'.
Then I can not call it.
I wonder why?
By the way, it seems that the library provider did not want us to use these kinds of classes.
How do they do this?
The Java language allows class identifiers to be obscured by package identifiers. In your case the class com.xx.a is obscured by the package com.xx.a.
From the Java Language Specification:
6.3.2 Obscured Declarations
A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type or a package. In these situations, the rules of §6.5 specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it may sometimes be impossible to refer to a visible type or package declaration via its simple name. We say that such a declaration is obscured.
I must say that the rules in §6.5 for classifying the meaning of an identifier are far from clear though.
The reason why you still happen to have a copy of a library that violates this rule is because the rule does not apply for class files / JAR files and the JVM.
This means that you can have such naming conflicts in JAR files, but you'll never see it as output from javac. The tool that has produced these class / package names is most likely a code obfuscator which produces this kind of messy code to compress the size of the files and to obfuscate the code to prevent reverse engineering.
PS. At a closer look it may actually be a bug on the Eclipse side (assuming that's the IDE you're talking about). By letting an empty package name collide with a class name, Eclipse chokes on something javac accepts. The spec is hard to follow, but from what I can see, javac follows the spec in this case.
This is a common issue when decompiling jars.
The Compiler will get confused when there is a class and a subpackage with the same name. If you don't find a compiler with the option to append a prefix regarding the type(package, class variable) you have to refactor the source files. You can do that with regex by for example renaming every package declaration and import from
import A.B.C
to something like
import pkgA.pkgB.C.
Of course you can't do that for the external packages from the sdk or other libraries but most of the time the used obfuscator renames them in the same way so for renaming to letters from A-Z you could use something like:
RegexFindAll("import\s+(?:[A-Z]\s*.\s*)*([A-Z])\s*.\s*(?:[A-Z]\s*.\s*)*[A-Z]\s*;")
RegexFindAll("package\s+(?:([A-Z])\s*.\s*)*([A-Z])\s*;")
And from there on you can rename every package. If your IDE doesn't offer such functionality you can also rely on the terminal with following commands.
To find all the files by name recursively(extendable with filename filter)
find -follow from https://stackoverflow.com/a/105249/4560817
To iterate over the found filenames
sudo find . -name *.mp3 |
while read filename
do
echo "$filename" # ... or any other command using $filename
done
from https://stackoverflow.com/a/9391044/4560817
To replace text inside a file with regex
sed -i 's/original/new/g' file.txt from https://askubuntu.com/a/20416
You need to do this:
com.xx.a.a ma = new com.xx.a.a();
Or import the package:
import com.xx.a;
a ma = new a();
The library is likely obfuscated (e.g. using proguard) to reduce size, prevent reverse engineering and "hide" stuff you're not supposed to use. Even if you manage to create an instance of this class, I would recommend against it, as you don't know what it will do or how it can/should be used.
we can not do this in java:
com.xx.A
com.xx.A.yy
the package name clashes with a class in the parent package,.
According to the JLS, it is valid syntax to have multiple classes in one file, so long as only a single class in the file is public. As I understand it, this is usually to allow small classes referred to only in a single file to be maintained within that file.
One area I'm not sure about is if other files in the same package are able to safely refer to that second class in the original file - by the scoping rules it would seem valid, but I'm not sure if it is a problem while compiling. I have seen it work quite frequently, but I've also been told by other developers on the project that there are occasional build issues finding the symbol in question after making changes elsewhere in the system. Is this setup of referring to package private classes embedded in other class' files introducing some sort compilation order dependency into the process that is making the build fragile?
Yes, that should be absolutely fine - unless you've got a badly-configured build system, basically. You should probably be compiling all the source for the same package in one go anyway.
I can see it potentially causing a problem for some build systems which try to work out what needs recompiling - if they assume that the name of the source file matches the name of the resulting class, they could get confused here (even if you don't have multiple classes in the same file) but that's a tool problem rather than a language problem.
Note that normally if I have "small classes referred to only in a single file" I'd normally make them private static nested classes:
public class OuterClass
{
// Normal code...
// Only used within OuterClass
private static class Foo
{
}
}
That's cleaner (IMO) than giving something package-private access, if it's really only intended to be used from a single class.
i often have in java projects a lot of small helper("storage") classes like
2-Tuple, 3-Tuple, Point, .. (think you know what i mean)
Classes that mostly only have class variables, a constructor and getters/setters.
And in my current project, i wanted to store those small classes, that are often used in a lot of other classes in the project in a seperate package. But i do not really know how to name it (my motherlanguage is not english, but code should be for english readers.)
Hope you can give me an answer on this little questions.
Greetings
:)
Different people would name these differently as the names are a matter of personal choice.
A few options:
If the storage classes conform to the Javabeans conventions, you could add the suffix "Bean" eg PointBean
I have also seen a suffix of "DO" or "VO" being used to denote a "data object" or "value object". eg PointDO
You could leave the class name as is eg Point. However if you feel that it does not convey the fact it is a storage class, try to make the package name convey that fact eg
com.xyz.valueobjects.Point
or
com.xyz.dataobjects.Point
or
com.xyz.storage.Point
Personally I like to use style #3.
I'd stick those kinds of classes in a *.util package.
I'd go with something like:
utils or the more verbose utilities
you can then break that down further if you need to:
utils.data for data-related utility classes, for example.
Additionally, there's a question here on whether to pluralise or not: Naming convention for utility classes in Java
For your information the "storage classes" you are referring to are called Java Beans. Using the popular model view controller design pattern; these would be your model. So lets say you want to put them in a package called model and the domain name of your company is mycompany.com, then the propper java naming convention would be com.mycompany.model; add this line as the first line of code (before any import statements) to all of your Java bean classes:
package com.mycompany.model;
You must also move your Java bean files into a folder structure that is the same. Lets say the file with your main method is in the directory /%ProjectHome%/, then your Java Beans go in a folder /%ProjectHome%/com/mycompany/model/
To compile these files you will now have to change to your /%ProjectHome%/ directory then type javac com/mycompany/model/*.java
Then you will be able to import these files from your other java classes by typing
import com.mycompany.model.*;
Also note, that the Java convention for package names is all lower case, as not to clash with the name space of Class names.
Hope this helps.
I believe what you're doing is using objects purely for storing data (no behaviour). And since you're talking about tuples, I assume these are used for transferring data to/from your database, so perhaps just "data objects"?