4

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?

corazza
  • 31,222
  • 37
  • 115
  • 186
hguser
  • 35,079
  • 54
  • 159
  • 293

5 Answers5

6

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.

user85421
  • 28,957
  • 10
  • 64
  • 87
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Does it mean that the obfuscation is done on the class file not the .java source code? – hguser Mar 06 '12 at 13:12
  • Yes, if they used a standard Java compiler that's exactly what it means. – aioobe Mar 06 '12 at 13:14
  • In current versions of JLS, obscuring is specified in §6.4.2 not 6.3.2, but more importantly, obscuring only defines how a _simple_ name is interpreted. `com.xx.a`, however, is a qualified name, not a simple name. Hence, obscuring doesn't apply. – Stephan Herrmann Sep 08 '18 at 11:49
1

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

FerhatC
  • 41
  • 5
0

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();
adarshr
  • 61,315
  • 23
  • 138
  • 167
0

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.

claesv
  • 2,075
  • 13
  • 28
  • Even the code are obfuscated,but I wonder why it can work? As simaremare say,we can not do that in java,so I wonder if the obfuscation is done on the generated class file? – hguser Mar 06 '12 at 13:05
0

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,.

simaremare
  • 401
  • 2
  • 10