I am able to run the following example code
//main class
String a="Menu";
Object o = Class.forName("org.test."+a).newInstance();
//Menu class
public class Menu()
{
public Menu()
{
System.out.println("con called");
}
}
It runs fine, but when I obfuscate the code I get a no ClassNotFoundException.
I am using netbean 6.9.1 . In Additional obfusating setting i added -keepnames class org.test.Menu. But still not working. Any solution?
The trivial reason: The obfuscator changed the name of org.test.Menu to something else (package name changed and/or class name changed). And the obfuscator can't "refactor" the classes so that String based class names in other class files are changed too.
If this is the case, tell the obfuscator not to touch the org.test package (keep that name and don't obfuscate the name of the class(es) inside).
This is by design. Obfuscation changes the names of all of your public identifiers (including class names), and so if you're referring to any of them via strings (like with Class.forName, or other forms of reflection), and especially strings that you calculate ("org.test." + a) that will break.
If you need to demand-load Menu via Class.forName, then you cannot obfuscate the Menu class.
It's been a long time since I looked at obfuscators, but IIRC some may be able to rewrite some strings for you if you tag them in a particular way; check the docs on the one you're using to see if it can. But even then, it's unlikely they'd be able to rewrite something like "org.test." + a for you. You'd have to have the full name in a single string.
Obfuscation Changes the Tokens, Identifiers so your hard coded string ("org.test.Menu") for name wouldn't be found.
Obfuscation changes the names of classes and so the name of class Menu will be changed to something else.
When you obfuscate the code it changes class name by some a,b' and so on..
Related
I am currently learning about Reflection and I have seen most of the similar posts to my question on stack however, I don't feel they fully answer my question on it.
I want to know if I have a package in Eclipse can I use Reflection to iterate through the classes in the package to find which one implements interface. There is only 1 interface so either they implement it or don't.
Could anyone provide a basic clear example as to how I may go about this? I have been told by some that this is just not possible whilst other people say it is possible using Reflection.
Thank you to any one who could help clear this matter.
Reflection API does not provide directly facility to iterate over classes in specific package. It concentrates on discovery of class once you have it.
To achieve what you want to have to read the class path of your application, iterate over the class path, open jars and go into directories, find files that end with *.class and get them as resource like getResource(full_class_name) or get it directly as class using Class.forName().
This method has a limitation: you will not see classes loaded by custom class loaders.
Unless this is an exercise I'd recommend you to use Reflections library that does everything you need and (probably) even more... :)
Some more details
Java system property "java.class.path" contains class path of your application separated with ; on Windows and : on Unix.
So, this is the way you can get list of class path elements:
System.getProperty("java.class.path").split(File.pathSeparator)
Here is some code sample that can help you to start:
for (String cpElement : System.getProperty("java.class.path").split(File.pathSeparator)) {
File cpFile = new File(cpElement);
if (!cpFile.exists()) {
continue;
}
if (cpFile.isDirectory()) {
findClassesInDirectory(cpFile);
} else {
findClassesInArchive(cpFile);
}
}
Etc, etc. I am leaving implementation of findClassesInDirectory() and findClassesInArchive() for you. Nice exercise. Have fun.
have you heard of guava-libraries for Java.
They provide useful utilities regarding reflection.
For your specific problem, I would have a look a the TypeToken and the method getTypes().
Good luck
yes you can so it. But with eclipse its more of an AST tree translation and not reflections. See if you want to iterate over source code and see which source file implements the interface you probably need AST tree walkers to do that. But on the other hand if you want to introspect at runtime the class files in a given package or a folder which implement the said interface then you need Reflections to do that. Either way its doable. I cant give you the code to try that out as a little time with Google will give you the answers you need though not all at the same place.
Reflection does not provide all operations for a total inspection.
For a known class one can get the physical URL of a class SomeClass using:
CodeSource codeSource = SomeClass.class.getProtectionDomain().getCodeSource();
if (codeSource == null) {
// Run-time class; URL into the rt.jar.
} else {
URL url = codeSource.getLocation();
// "file:/.... /classes/.../SomeClass.class"
// "jar:file:/... /someJar.jar!/.../SomeClass.class"
}
For Java run time classes (rt.jar) codeSource will be null.
On the URL of the jar you can open a (zip) file system, and walk through folders as any real file system.
You'll probably want to inspect classes without $ in the name (embedded, generated anonymous classes): only fileName.matches("[^$]+\\.class").
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.
Guys, here is my problem: I have some class which is used in many places in my project. And I must replace this class with another from jar provided. Is there any ways to refactor this? I suppose this is a simple problem, but I dont know how to solve it.
Its not about replacing source code - what I want is to replace all class usages by class from my library and be able to completely remove my own class. Imagine I have created my own StringUtils and have found out that there is a apache.common StringUtils library, and now I want to use it everywhere in my code. And the signatures of class methods are not a problem: they coincide.
?
There is this "migrate" function. Right click in whatever class -> Refactor -> Migrate.
It's a bit annoying that you have to create a new migrate set and you can't run it from scratch. But it does exactly what you need.
You pick class or package to migrate and tell it to which class or package it should change. Press run and all usages are rewritten. Then you're free to delete the old class because there will be no usages.
EDIT: In the newer versions it isn't in the context menu anymore. Just go to the menu on top - Refactor - Migrate (or simply pres shift twice and type migrate).
Cheers!
If you are using static methods (like your StringUtils example suggests), delegate to the new class in your previous implementation like
public static String myOldMethod(String argument) {
return MyNewClass.myNewMethod(argument);
}
then select Refactor->Inline and select "All invocations and remove the method" in the option dialog. In this way you can handle method name changes and argument order changes are well.
I found it to be easy to use delete and rename:
Temporarily delete TargetClass (delete without usages).
Rename SourceClass to TargetClass with usages.
Restore TargetClass from VCS or local history.
The simplest way is to write a method mapping what you would like to inline.
Say you have a method
enum MyStringUtils {
public static boolean containsAnyCase(String searchFor, String searchIn) {
// something
}
}
// calling code
boolean found = MyStringUtils.containsAnyCase(find, in);
You want to use StringUtils.containsIgnoreCase however the class name, method name and order arguments are different.
So you change the body of the method to call the desired method instead.
public static boolean containsAnyCase(String searchFor, String searchIn) {
return StringUtils.containsIgnoreCase(searchIn, searchFor);
}
Select the method and <Crtl> + <Alt> + N. This will offer to inline this method everywhere and deletes your method. Your caller now looks like
boolean found = StringUtils.containsIgnoreCase(in, find);
This will work even if the original class uses an import of the class, import static of the method or no import at all.
Although I am not an expert in IntelliJ I can tell you that generally in java the class loading is done sequentially. I mean the class loader is looking for classes sequentially, so if the same class presents in class path several times it will take the first version.
So, it depends on how are you running your application. If for example you are using command line like java -cp lib.jar;myapp.jar com.mycompany.Main and both lib.jar and myapp.jar contain the same class Util the lib.jar version will be used.
If you want to achieve the same effect when running from IDE try to check the project properties. Probably you can control the order of library jars relatively to your project's classes? If not, probably you can add jars to bootstrap classpath. In this case add your lib.jar to bootstrap classpath (just to work on your IDE).
Good luck.
Is it possible to load a class by name if you don't know the whole package path? Something like:
getClassLoader().loadClass("Foo");
The class named "Foo" might be around, might not be - I don't know the package. I'd like to get a listing of matching classes and their packages (but not sure that's possible!),
Thanks
Nope. The Java ClassLoader.loadClass(String) method requires that class names must be fully qualified by their package and class name (aka "Binary name" in the Java Language Specification).
If you don't know the package, you don't know the name of a class (because it's part of the fully qualified class name) and therefore cannot find the class.
The Java class loading mechanism basically only allows you to do one thing: ask for a class with its fully qualified name, and the classloader will either return the class or nothing. That's it. There#s no way to ask for partial matches, or to list packages.
Contrary to the previous answers, and in addition to the answers in the question #reader_1000 linked to:
This is possible, by essentially duplicating the logic by which Java searches for classes to load, and looking at all the classfiles. Libraries are available that handle this part, I remember using Reflections. Matching classes by unqualified name isn't their major use case, but the library seems general enough and this should be doable if you poke around. Do note that this will, very likely, be a fairly slow operation.
Using java Reflections:
Class.forName(new Reflections("com.xyz", new SubTypesScanner(false)).getAllTypes().stream()
.filter(o -> o.endsWith(".Foo"))
.findFirst()
.orElse(null));
Even if you don't know the package name, sites like jarFinder might know it