I am trying to find the method signature of the caller method. I need to do this because the code I'm writing gets obfuscated and a lot of methods get overloaded. I'm trying to ignore calls from a certain method that has the signature At the moment my code looks like this
StackTraceElement caller = Thread.currentThread().getStackTrace()[2];
String cn = caller.getClassName();
String mn = caller.getMethodName();
if(cn == "net.minecraft.client.Minecraft" && (mn == "displayGuiScreen" || mn == "a")){ // displayGuiScreen is for non-obfuscated, a is for obfuscated. Doesn't work because 2 other methods that call it are also called a when obfuscated
System.err.println("Skipped");
return;
}
Can anyone help me with this? Thanks
Try to use asm library, and I've just found I think related to you post, try to read and find out example, post
You might be able to use AspectJ with compile-time weaving. You can use around advice to do nothing if the caller is the displayGuiScreen method. This will only work if you compile all the code that calls your class. Compile-time weaving is necessary because you must do it before obfuscation and for all callers of your method. You should be able to do something like this:
aspect IgnoreCallsFromDisplayGuiScreen {
void around(): call(void MyClass.myMethod()) && withincode(void Minecraft.displayGuiScreen()) {
return;
}
}
First verify that your code works without obfuscation.
Second, find the obfuscation map, which is an output of the obfuscation program.
Third verify that your obfuscator updated the string to match the new method signature as it is detailed in the map. Odds are only the class name and method names have changed.
If you do not have a match, either look to your obfuscator for an option to rewrite strings that look like reflection calls, or use asm to rewrite the string within the compiled class that didn't get the update.
Related
I have to deal with a legacy application that has no tests. So before I begin refactoring I want to make sure everything works as it is.
Now imagine the following situation:
public SomeObject doSomething(final OtherObject x, final String something) {
if(x == null) throw new RuntimeException("x may not be null!");
...
}
Now I want to test that null check, so to be sure it works and I don't lose it once I refactor.
So I did this
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, "testString");
}
Now, this works of course.
But instead of "testString" I'd like to pass in a random String.
So I tried with:
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, Mockito.anyString());
}
But this is not allowed., as I get org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
... You cannot use argument matchers outside of verifications or stubbing
I do understand the meaning of this, but I wonder whether I can still manage to do what I want without parameterizing my test or the like.
The only libraries I may use are Junit, AssertJ, Mockito and Powermock.
Any ideas?
Tests should be deterministic. Using random values in a test makes it difficult to reproduce behavior when debuging a failed test. I suggest that you just create a String constant for the test such as "abcdefg".
Well, like Mockito is trying to tell you via that exception, that's not really how you'd use anyString. Such methods are only to be used by mocks.
So, why not try testing with an actual random string? My personal favorite in such a scenario: java.util.UUID.randomUUID().toString(). This will virtually always generate a brand new string that has never been used for your test before.
I'd also like to add that if you are writing tests for your SomeObject class that you should avoid mocking SomeObject's behavior. From your example, you weren't exactly doing that, but it looked like you might be going down that route. Mock the dependencies of the implementation you're trying to test, not the implementation itself! This is very important; otherwise you aren't actually testing anything.
You are mixing up concepts here.
All those "mocking" helpers like anyString() are meant to be used when configuring a mock object.
But when you check your testing code:
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, "testString");
}
you will find: there is absolutely no mocking involved for this test. You simply can't use those Mockito calls in that place; because "there is no Mockito" in that place.
And just for the record - no need to go overboard here anyway. Your logic is very clear here: when the first argument is null, then you throw that exception. Thus it really doesn't matter at all what comes in as second argument. So thinking for an hour how to test null with any second argument is, well, in my eyes: waste of your time.
Final hint: there is java.lang.Objects
And that class has a nice check for null, so my production code only looks like
public SomeObject doSomething(final OtherObject x, final String something) {
Objects.requireNonNull(otherObject, "otherObject must not be null");
Objects.requireNonNull(something, "something must not be null");
Only difference there: requires... throws NullPointerExceptions
Final finally: some people suggest to put final on every parameter; but I wouldn't do that. It adds no value in 99% of all cases. It just means that you have more code to read; for no good reasons. But that is a question of style.
EDIT on the comment about having a test to check for potential future changes: you shouldn't do that:
To a certain degree, how your input is verified is an implementation detail. You don't test for implementation details. In other words:
Your method has a certain contract (that you, for example specify informally by writing a javadoc that says "throws NPE on null input"). Your tests should verify exactly that current contract. And the contract is: throws if first argument is null.
And maybe another point of view; as I still think you are wasting your time here! You should make sure that all your interfaces are clear, easy to understand, and easy to use. That they allow users of your code to do the right thing easily; and prevent him from doing wrong things. That is what you should focus on - the quality of your interfaces as a whole!
So instead of worrying how you could write a test for potential future changes; just make sure that your code base is overall consistent.
Well i do not have much knowledge of mockito but you can always create your own random string generator. maybe that can work and u can modify more types of inputs in it
I need to replace a method call inside java method.
Consider a scenario :
public void enterCatle(){
if(PaltformRuntime.returnSuggestion()){
System.out.println("entered into the castle");
}
}
I need to replace a returnSuggestion() with some other method call.I am able to achieve this by overriding the edit(MethodCall m) in the
Expression editor of java assist.
But there is a scenario as follows.
public void enterCatle(){
if(PaltformRuntime.returnSuggestion() && ElementRegistry.returnSuggestion()){
System.out.println("entered into the castle");
}
}
Here inside the enterCatle() in the if statement there are 2 returnSuggestion() from different classes. What I need is to replace the first returnSuggestion() alone.
I tried to identify the exact method call to replace by conditions like m.getLineNumber() m.where().getName() with this things I am able to narrow down to the particular method and exact line number. Now the problem is, if the same method is used twice in the same line, both get replaced.
How can I identify the exact method to replace? Is there any way to get the context of the method call like which position the method call is placed so that I can map by java assist.
or is there any other approach for this scenario?
I have package ( of java classes ) in my project.Which need to be removed under some requirement.
I have to compile my project to target
Highend
and
lowend
Requirement constraints
Package need to be there in Highend, and should not be there for lowend.
My code base is same for both the targets
To achive this requiment I want a way to define
class myclass{
static final boolean isEnable = false;
public void API1(){
if(isEnabled){
//function logic
}
}
public boolean API2(){
if(isEnabled){
//function logic
//return value
}
else
return false;
}
}
Although the "static final " private variable provide a solution to reduce my class size as the is the isEnabled code is false. the compiler remove the bytecode from the complied class.But using this I think it won't solve my problem, it reduces the class size for lowend target But the the function persist which return some default value.
Is there any better way or design pattern is solve this problem, as with the current solution I have to made changes in all API of the classes present in the package, Although I have to remove all complete package.
This requirement is related to a java package in Android, So I am including it Android in the tags
You may want to restructure your code so that API2 is contained in a class which gets eliminated altogether in the lowend version. Moreover, as the callers of API2 get no sane answer in the lowend version, you may be able to eliminate the test inside of API2, too. I mean the following
nobody uses the class containing API2
the whole class gets eliminated
the method needs no isEnabled check
While this sounds good to me, note that it's just one design goal, don't try too hard to follow it, so that you don't end with some insane design. If there are tens of isEnabled checks, then you're (probably) doing something wrong.
You may also want to use a simple lowend implementation overridden by a highend implementation like
class LowendSomething {
boolean doFancyStuff() {
throw new BuyTheHighendVersionException();
}
}
class HighendSomething {
boolean doFancyStuff() {
... do fancy stuff
}
}
together with a line like
LowendSomething something =
isEnabled ? new HighendSomething() : new LowendSomething();
Can such tests have a good reason to exist?
Some classes use toString for more than just user-readable informative string. Examples are StringBuilder and StringWriter. In such a case it is of course advisable to test the method just like any other business-value method.
Even in the general case it is good practice to smoke-test toString for reliability (no exceptions thrown). The last thing you need is a log statement blowing up your code due to an ill-implemented toString. It has happened to me several times, and the resulting bugs are of the nastiest kind, since you don't even see the toString call in the source code—it's implicitly buried inside a log statement.
The question is not should I test toString(), but do you care about the result of toString()? Is it used for something? If so, then yes, test it.
If a method gets used for something real, then test it.
Obvious answer is „no, it's just a waste of time“. But for many classes, first of all value-wrappers, toString should be overloaded and deliver more information that just org.package.ClassName#2be2befa
So my propostal test for toString is:
#Test
public final void testToString() {
assertFalse(new MyClass().toString().contains("#"));
}
It also increases test converage what is at least not bad.
If the result of the method is important to you, you should test it, otherwise you can just ignore that.
I am going to go against the general advise and say testing a toString method definitely has its place. Applications I have work on log a lot, especially if you turn on debug or trace level logs. If I am relying on the logs to help identify a bug and some fields from my POJO are not present because some developer forgot to regenerate the toString method, this is a huge setback!
The problem is that the toString method is an absolute pain to test as their is no fixed format or a clear way to test it. I would recommend not writing a test yourself, but using a library such as ToStringVerifier
#Test
public void testToString()
{
ToStringVerifier.forClass(User.class).verify();
}
I came across this method in the JDK
From com.sun.org.apache.xml.internal.serializer.Version;
public static int getDevelopmentVersionNum()
{
try {
if ((new String("")).length() == 0)
return 0;
else
return Integer.parseInt("");
} catch (NumberFormatException nfe) {
return 0;
}
}
Is this doing anything more than return 0?
I feel like I am missing something. I can only assume this is generated code. ;)
It looks like this file is generated from the following Version.src file by textual substitution. So, when #version.DEVELOPER# variable is empty, the code in question is generated. length() check is needed to return 0 in this case.
I think "" is replaced with some string from a configuration file before release. In this case it is empty, but it may also contain a number. If you consider "" to be a variable, this code makes some sense.
The javadoc on the method indicates that it's meant to designate a development drop that is work in progress. So I would say it makes as much sense as anything else that's meant for internal development use only. It could be that they "wash away" any actual version information from this method once they do a release. Either way, I would not place any significance on it. Unless you are a developer at oracle, working on this particular package.
Yes, there's probably a generator/preprocessor, which outputs a string in both if's.
If this string is a number, the method returns its value as a number. If it's empty (as in this case) or not a number, it returns 0.
Looks like the original xalan has a similiar implementation - at least I found the same lines for xalan 2.7.1 at grepcode
It really doesn't make any sense, to much effort for a method that always returns 0 ;) But from looking at the javaDoc of Version and this method I get the impression that all of this is (or was) work in progress - some sort of implementation stub where one can simply enter (hardcode) a version number. For now, the else block and the catch block are unreachable code.
Maybe Version.java is/will be autogenerated and the processor may generate this method with a real value instead of "" - in that case it would make sense to secure the method, as the value from the config file may not represent an integer.